Initial commit
This commit is contained in:
parent
ff795d2b6e
commit
2fbacc0544
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
build
|
||||
*~
|
||||
GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
TAGS
|
||||
56
Makefile
Normal file
56
Makefile
Normal file
@ -0,0 +1,56 @@
|
||||
SOURCES = $(wildcard source/*.sv)
|
||||
TOP = sugar_lissajous
|
||||
PCF = icesugar.pcf
|
||||
|
||||
FAMILY = up5k
|
||||
PACKAGE = sg48
|
||||
FREQ = 30
|
||||
|
||||
#DOSVG = --placed-svg place.svg --routed-svg route.svg
|
||||
# nextpnr --randomize-seed write_verilog $(TOP).v
|
||||
|
||||
BUILD_DIR ?= build
|
||||
|
||||
TOP_BIN = $(BUILD_DIR)/$(TOP).bin
|
||||
TOP_ASC = $(BUILD_DIR)/$(TOP).asc
|
||||
TOP_JSON = $(BUILD_DIR)/$(TOP).json
|
||||
|
||||
all: $(TOP_BIN)
|
||||
|
||||
# Make bitstream
|
||||
$(TOP_BIN): $(TOP_ASC)
|
||||
icepack $(TOP_ASC) $(TOP_BIN)
|
||||
|
||||
# Place and rouite
|
||||
$(TOP_ASC): $(TOP_JSON) $(PCF)
|
||||
nextpnr-ice40 -q -l $(BUILD_DIR)/nextpnr.log --$(FAMILY) --package $(PACKAGE) \
|
||||
--freq $(FREQ) --top $(TOP) --pcf $(PCF) --asc $(TOP_ASC) --json $(TOP_JSON) \
|
||||
$(DOSVG)
|
||||
|
||||
# Synthesys
|
||||
$(TOP_JSON): $(SOURCES)
|
||||
mkdir -p $(BUILD_DIR)
|
||||
yosys -q -l $(BUILD_DIR)/yosys.log -p \
|
||||
"proc; alumacc; share -fast; opt -full; synth_ice40 -top $(TOP) -json $(TOP_JSON) -abc2" \
|
||||
$(SOURCES)
|
||||
|
||||
# Timing analysis
|
||||
timing: $(TOP_ASC)
|
||||
icetime -d $(FAMILY) -t -c $(FREQ) -r $(BUILD_DIR)/timing.log $(TOP_ASC)
|
||||
|
||||
# Program
|
||||
prog: $(TOP_BIN)
|
||||
icesprog -w $(TOP_BIN)
|
||||
|
||||
# Clean
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR)
|
||||
|
||||
# Convert SVG to PNG
|
||||
png: route.png place.png
|
||||
|
||||
route.png: route.svg
|
||||
inkscape --export-type=png -o route.png -D -d 100 route.svg
|
||||
|
||||
place.png: place.svg
|
||||
inkscape --export-type=png -o place.png -D -d 150 place.svg
|
||||
16
README.md
Normal file
16
README.md
Normal file
@ -0,0 +1,16 @@
|
||||
Light-organ based on [iCESugar 1.5](https://github.com/wuxx/icesugar)
|
||||
board (Lattice iCE40UP5k), nameless SPI TFT LCD display from AliExpress,
|
||||
and sound capture board [Dual MCP3102](https://github.com/punzik/dual-mcp3201-pmod).
|
||||
|
||||
Project is synthesized by [Yosys](https://github.com/YosysHQ/yosys), routed and
|
||||
placed by [nextpnr](https://github.com/YosysHQ/nextpnr), verefied by
|
||||
[iverilog](https://github.com/steveicarus/iverilog) and
|
||||
[verilator](https://github.com/verilator/verilator). For scripting, prototyping and
|
||||
GUI use [Racket](https://racket-lang.org/) and [GNU
|
||||
Octave](https://www.gnu.org/software/octave/index).
|
||||
|
||||
Video 1: https://youtu.be/R9meEMrbPAM
|
||||
|
||||
Video 2: https://youtu.be/H2083E0BFIM
|
||||
|
||||

|
||||
BIN
doc/ILI9341 Datasheet.pdf
Normal file
BIN
doc/ILI9341 Datasheet.pdf
Normal file
Binary file not shown.
61
icesugar.pcf
Normal file
61
icesugar.pcf
Normal file
@ -0,0 +1,61 @@
|
||||
# iCESugar Board (iCE40UP5K-QFN48)
|
||||
|
||||
set_io -nowarn LED_R_N 39
|
||||
set_io -nowarn LED_G_N 40
|
||||
set_io -nowarn LED_B_N 41
|
||||
|
||||
set_io -nowarn SW[0] 18
|
||||
set_io -nowarn SW[1] 19
|
||||
set_io -nowarn SW[2] 20
|
||||
set_io -nowarn SW[3] 21
|
||||
|
||||
set_io -nowarn CLK12 35
|
||||
|
||||
set_io -nowarn UART_RX 4
|
||||
set_io -nowarn UART_TX 6
|
||||
|
||||
set_io -nowarn USB_DP 10
|
||||
set_io -nowarn USB_DN 9
|
||||
set_io -nowarn USB_PUP 11
|
||||
|
||||
# PMOD 1
|
||||
set_io -nowarn P1_1 10
|
||||
set_io -nowarn P1_2 6
|
||||
set_io -nowarn P1_3 3
|
||||
set_io -nowarn P1_4 48
|
||||
set_io -nowarn P1_9 47
|
||||
set_io -nowarn P1_10 2
|
||||
set_io -nowarn P1_11 4
|
||||
set_io -nowarn P1_12 9
|
||||
|
||||
# PMOD 2
|
||||
set_io -nowarn P2_1 46
|
||||
set_io -nowarn P2_2 44
|
||||
set_io -nowarn P2_3 42
|
||||
set_io -nowarn P2_4 37
|
||||
set_io -nowarn P2_9 36
|
||||
set_io -nowarn P2_10 38
|
||||
set_io -nowarn P2_11 43
|
||||
set_io -nowarn P2_12 45
|
||||
|
||||
# PMOD 3
|
||||
set_io -nowarn P3_1 34
|
||||
set_io -nowarn P3_2 31
|
||||
set_io -nowarn P3_3 27
|
||||
set_io -nowarn P3_4 25
|
||||
set_io -nowarn P3_9 23
|
||||
set_io -nowarn P3_10 26
|
||||
set_io -nowarn P3_11 28
|
||||
set_io -nowarn P3_12 32
|
||||
|
||||
# PMOD 4
|
||||
set_io -nowarn P4_1 21
|
||||
set_io -nowarn P4_2 20
|
||||
set_io -nowarn P4_3 19
|
||||
set_io -nowarn P4_4 18
|
||||
|
||||
#spi
|
||||
set_io -nowarn SPI_SS 16
|
||||
set_io -nowarn SPI_SCK 15
|
||||
set_io -nowarn SPI_MOSI 17
|
||||
set_io -nowarn SPI_MISO 14
|
||||
5
source/.dir-locals.el
Normal file
5
source/.dir-locals.el
Normal file
@ -0,0 +1,5 @@
|
||||
;;; Directory Local Variables
|
||||
;;; For more information see (info "(emacs) Directory Variables")
|
||||
|
||||
((verilog-mode . ((flycheck-verilator-include-path . ("." "../../local/share/yosys/ice40"))
|
||||
(verilog-library-directories . ("." "../../local/share/yosys/ice40")))))
|
||||
9
source/assert.vh
Normal file
9
source/assert.vh
Normal file
@ -0,0 +1,9 @@
|
||||
`ifndef _ASSERT_VH_
|
||||
`define _ASSERT_VH_
|
||||
|
||||
`define assert(assertion) \
|
||||
if (!(assertion)) begin \
|
||||
$error("ERROR: Assertion failed in %m: assertion");\
|
||||
end
|
||||
|
||||
`endif
|
||||
29
source/circle-table.rkt
Normal file
29
source/circle-table.rkt
Normal file
@ -0,0 +1,29 @@
|
||||
#lang racket
|
||||
|
||||
(define (gen-circle-quadrant len)
|
||||
(map (lambda (n)
|
||||
(let ((angle (/ (* 2 pi n) len)))
|
||||
(cons (sin angle)
|
||||
(cos angle))))
|
||||
(range (/ len 4))))
|
||||
|
||||
(define (print-xy-table table)
|
||||
(define (->hex x)
|
||||
(~a (number->string (inexact->exact (round x)) 16)
|
||||
#:min-width 2 #:align 'right #:pad-string "0"))
|
||||
(for-each
|
||||
(lambda (c)
|
||||
(printf "~a~a\n"
|
||||
(->hex (* 255 (car c)))
|
||||
(->hex (* 255 (cdr c)))))
|
||||
table))
|
||||
|
||||
;;; MAIN
|
||||
(let ((x0 0)
|
||||
(y0 0)
|
||||
(len 1024))
|
||||
|
||||
(with-output-to-file (format "quadrant_~a.rom" (/ len 4))
|
||||
(lambda ()
|
||||
(print-xy-table
|
||||
(gen-circle-quadrant len)))))
|
||||
82
source/circle_1024.sv
Normal file
82
source/circle_1024.sv
Normal file
@ -0,0 +1,82 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
|
||||
module circle_1024
|
||||
(input wire clock,
|
||||
input wire reset,
|
||||
|
||||
input wire [9:0] angle,
|
||||
input wire [7:0] r,
|
||||
input wire [7:0] x0,
|
||||
input wire [7:0] y0,
|
||||
|
||||
output wire [7:0] x,
|
||||
output wire [7:0] y,
|
||||
|
||||
input wire req_i,
|
||||
output reg ack_o);
|
||||
|
||||
localparam QUADR_LEN = 256;
|
||||
localparam QUADR_ROM_FILE = "quadrant_256.rom";
|
||||
localparam QUADR_CW = $clog2(QUADR_LEN);
|
||||
logic [15:0] q_rom[QUADR_LEN];
|
||||
initial $readmemh(QUADR_ROM_FILE, q_rom, 0, QUADR_LEN-1);
|
||||
|
||||
logic [QUADR_CW-1:0] q_addr;
|
||||
logic [7:0] kx, ky;
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
{kx, ky} <= q_rom[q_addr];
|
||||
|
||||
logic [15:0] macx_o, macy_o;
|
||||
logic xsub, ysub;
|
||||
|
||||
ice40_2mac8x8 circle_mac
|
||||
(.clock, .reset,
|
||||
.a0(r),
|
||||
.b0(kx),
|
||||
.s0({x0, 8'b0}),
|
||||
.sub0(xsub),
|
||||
.y0(macx_o),
|
||||
|
||||
.a1(r),
|
||||
.b1(ky),
|
||||
.s1({y0, 8'b0}),
|
||||
.sub1(ysub),
|
||||
.y1(macy_o));
|
||||
|
||||
assign q_addr = angle[8] ? 8'd255 - angle[7:0] : angle[7:0];
|
||||
assign xsub = angle[9];
|
||||
assign ysub = angle[8] == angle[9] ? 1'b0 : 1'b1;
|
||||
assign x = macx_o[15:8];
|
||||
assign y = macy_o[15:8];
|
||||
|
||||
enum int unsigned {
|
||||
ST_IDLE = 0,
|
||||
ST_GET_K,
|
||||
ST_MAC
|
||||
} state;
|
||||
|
||||
always_ff @(posedge clock, posedge reset)
|
||||
if (reset) begin
|
||||
state <= ST_IDLE;
|
||||
ack_o <= 1'b0;
|
||||
end
|
||||
else
|
||||
case (state)
|
||||
ST_IDLE:
|
||||
if (req_i)
|
||||
state <= ST_GET_K;
|
||||
|
||||
ST_GET_K: begin
|
||||
ack_o <= 1'b1;
|
||||
state <= ST_MAC;
|
||||
end
|
||||
|
||||
ST_MAC: begin
|
||||
ack_o <= 1'b0;
|
||||
state <= ST_IDLE;
|
||||
end
|
||||
endcase
|
||||
|
||||
endmodule // circle
|
||||
8
source/fig_circle_8x8.rom
Normal file
8
source/fig_circle_8x8.rom
Normal file
@ -0,0 +1,8 @@
|
||||
00 00 3f 3f 3f 3f 00 00
|
||||
00 3f 7f 7f 7f 7f 3f 00
|
||||
3f 7f bf bf bf bf 7f 3f
|
||||
3f 7f bf ff ff bf 7f 3f
|
||||
3f 7f bf ff ff bf 7f 3f
|
||||
3f 7f bf bf bf bf 7f 3f
|
||||
00 3f 7f 7f 7f 7f 3f 00
|
||||
00 00 3f 3f 3f 3f 00 00
|
||||
223
source/fig_drawer.sv
Normal file
223
source/fig_drawer.sv
Normal file
@ -0,0 +1,223 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
`include "assert.vh"
|
||||
|
||||
module fig_drawer #(parameter FIG_W = 8,
|
||||
parameter FIG_H = 8,
|
||||
parameter FIG_ROM_FILE = "fig_circle_8x8.rom")
|
||||
(input wire clock,
|
||||
input wire reset,
|
||||
|
||||
input wire [7:0] x_i,
|
||||
input wire [8:0] y_i,
|
||||
input wire [7:0] h_i,
|
||||
input wire [7:0] s_i,
|
||||
input wire [7:0] v_i,
|
||||
input wire req_i,
|
||||
output reg ack_o,
|
||||
|
||||
output reg [7:0] fb_x_o,
|
||||
output reg [8:0] fb_y_o,
|
||||
output reg [15:0] fb_color_o,
|
||||
output reg fb_req_o,
|
||||
input wire fb_ack_i);
|
||||
|
||||
initial begin
|
||||
`assert(FIG_W > 0);
|
||||
`assert(FIG_H > 0);
|
||||
|
||||
/* Check power of 2 */
|
||||
`assert(FIG_W == 1 << $clog2(FIG_W));
|
||||
`assert(FIG_H == 1 << $clog2(FIG_H));
|
||||
end
|
||||
|
||||
/* Figure bitmap */
|
||||
localparam FIG_SIZE = FIG_W * FIG_H;
|
||||
localparam FIG_W_CW = $clog2(FIG_W);
|
||||
localparam FIG_H_CW = $clog2(FIG_H);
|
||||
localparam FIG_CW = $clog2(FIG_SIZE);
|
||||
|
||||
logic [7:0] fig[FIG_SIZE];
|
||||
initial $readmemh(FIG_ROM_FILE, fig, 0, FIG_SIZE-1);
|
||||
|
||||
logic [FIG_CW-1:0] fig_addr;
|
||||
logic [7:0] fig_data;
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
fig_data <= fig[fig_addr];
|
||||
|
||||
/* Scale brightness */
|
||||
logic [31:0] mac_v_o;
|
||||
logic [7:0] fig_v;
|
||||
|
||||
assign fig_v = mac_v_o[15:8];
|
||||
|
||||
ice40_mac16x16 mac_v
|
||||
(.clock, .reset,
|
||||
.a({8'b0, fig_data}),
|
||||
.b({8'b0, v_i}),
|
||||
.s(32'b0),
|
||||
.sub(1'b0),
|
||||
.y(mac_v_o));
|
||||
|
||||
/* Convert HSV ro RGB */
|
||||
logic hsv_ready;
|
||||
logic rgb_valid;
|
||||
logic [7:0] r, g, b;
|
||||
|
||||
hsv2rgb hsv2rgb_i
|
||||
(.clock, .reset,
|
||||
.h(h_i), .s(s_i), .v(fig_v),
|
||||
.ready_i(hsv_ready),
|
||||
.r(r), .g(g), .b(b),
|
||||
.valid_o(rgb_valid));
|
||||
|
||||
/* FSM states */
|
||||
enum int unsigned {
|
||||
ST_IDLE = 0, // 0
|
||||
ST_READ_PIX, // 1
|
||||
ST_MULT_V, // 2
|
||||
ST_HSV_READY, // 3
|
||||
ST_RGB_WAIT, // 4
|
||||
ST_WAIT_FB, // 5
|
||||
ST_NEXT_PIXEL, // 6
|
||||
ST_DONE // 7
|
||||
} state, next;
|
||||
|
||||
/* FSM sync part */
|
||||
always_ff @(posedge clock, posedge reset)
|
||||
if (reset) state <= ST_IDLE;
|
||||
else state <= next;
|
||||
|
||||
/* Pixel coordinate */
|
||||
logic [FIG_W_CW-1:0] pix_x;
|
||||
logic [FIG_H_CW-1:0] pix_y;
|
||||
logic pix_reset, pix_next;
|
||||
|
||||
assign fig_addr = {pix_y, pix_x};
|
||||
|
||||
always_ff @(posedge clock)
|
||||
if (pix_reset) begin
|
||||
pix_x <= '0;
|
||||
pix_y <= '0;
|
||||
end
|
||||
else
|
||||
if (pix_next)
|
||||
if (pix_x == FIG_H_CW'(FIG_H-1)) begin
|
||||
pix_x <= '0;
|
||||
|
||||
if (pix_y == FIG_W_CW'(FIG_W-1))
|
||||
pix_y <= '0;
|
||||
else
|
||||
pix_y <= pix_y + 1'b1;
|
||||
end
|
||||
else
|
||||
pix_x <= pix_x + 1'b1;
|
||||
|
||||
/* Frame buffer control */
|
||||
logic [7:0] fb_x;
|
||||
logic [8:0] fb_y;
|
||||
logic [15:0] fb_color;
|
||||
logic fb_hold, fb_restore;
|
||||
logic fb_req;
|
||||
|
||||
always_ff @ (posedge clock, posedge reset)
|
||||
if (reset)
|
||||
fb_req_o <= 1'b0;
|
||||
else
|
||||
if (fb_req)
|
||||
fb_req_o <= 1'b1;
|
||||
else
|
||||
if (fb_ack_i)
|
||||
fb_req_o <= 1'b0;
|
||||
|
||||
assign fb_x = x_i + 8'(pix_x);
|
||||
assign fb_y = y_i + 9'(pix_y);
|
||||
|
||||
always_ff @ (posedge clock) begin
|
||||
if (rgb_valid) begin
|
||||
fb_color <= {r[7:3], g[7:2], b[7:3]};
|
||||
|
||||
if (~fb_hold)
|
||||
fb_color_o <= {r[7:3], g[7:2], b[7:3]};
|
||||
end
|
||||
|
||||
if (fb_restore)
|
||||
fb_color_o <= fb_color;
|
||||
end
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
if (fb_req) begin
|
||||
fb_x_o <= fb_x;
|
||||
fb_y_o <= fb_y;
|
||||
end
|
||||
|
||||
/* FSM comb part */
|
||||
always_comb begin
|
||||
next = state;
|
||||
pix_reset = 1'b0;
|
||||
pix_next = 1'b0;
|
||||
fb_req = 1'b0;
|
||||
fb_hold = 1'b0;
|
||||
fb_restore = 1'b0;
|
||||
ack_o = 1'b0;
|
||||
hsv_ready = 1'b0;
|
||||
|
||||
case (state)
|
||||
ST_IDLE:
|
||||
if (req_i) begin
|
||||
pix_reset = 1'b1;
|
||||
next = ST_READ_PIX;
|
||||
end
|
||||
|
||||
ST_READ_PIX:
|
||||
next = ST_MULT_V;
|
||||
|
||||
ST_MULT_V:
|
||||
if (fig_data == '0) begin
|
||||
pix_next = 1'b1;
|
||||
next = ST_NEXT_PIXEL;
|
||||
end
|
||||
else
|
||||
next = ST_HSV_READY;
|
||||
|
||||
ST_HSV_READY: begin
|
||||
hsv_ready = 1'b1;
|
||||
next = ST_RGB_WAIT;
|
||||
end
|
||||
|
||||
ST_RGB_WAIT:
|
||||
if (rgb_valid) begin
|
||||
if (fb_req_o && !fb_ack_i) begin
|
||||
fb_hold = 1'b1;
|
||||
next = ST_WAIT_FB;
|
||||
end
|
||||
else begin
|
||||
fb_req = 1'b1;
|
||||
pix_next = 1'b1;
|
||||
next = ST_NEXT_PIXEL;
|
||||
end
|
||||
end
|
||||
|
||||
ST_WAIT_FB:
|
||||
if (fb_ack_i) begin
|
||||
fb_restore = 1'b1;
|
||||
fb_req = 1'b1;
|
||||
pix_next = 1'b1;
|
||||
next = ST_NEXT_PIXEL;
|
||||
end
|
||||
|
||||
ST_NEXT_PIXEL:
|
||||
if (pix_x == '0 && pix_y == '0)
|
||||
next = ST_DONE;
|
||||
else
|
||||
next = ST_MULT_V;
|
||||
|
||||
ST_DONE: begin
|
||||
ack_o = 1'b1;
|
||||
next = ST_IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule // fig_drawer
|
||||
168
source/fig_ring.sv
Normal file
168
source/fig_ring.sv
Normal file
@ -0,0 +1,168 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
`include "assert.vh"
|
||||
|
||||
module fig_ring #(parameter POINT_COUNT = 32,
|
||||
parameter FADING = 1)
|
||||
(input wire clock,
|
||||
input wire reset,
|
||||
|
||||
input wire [7:0] pt_x,
|
||||
input wire [7:0] pt_y,
|
||||
input wire [7:0] pt_h,
|
||||
input wire pt_req_i,
|
||||
output reg pt_ack_o,
|
||||
|
||||
output reg [7:0] fig_x_o,
|
||||
output reg [8:0] fig_y_o,
|
||||
output reg [7:0] fig_h_o,
|
||||
output reg [7:0] fig_s_o,
|
||||
output reg [7:0] fig_v_o,
|
||||
output reg fig_req_o,
|
||||
input wire fig_ack_i);
|
||||
|
||||
initial begin
|
||||
`assert(POINT_COUNT > 0);
|
||||
`assert(POINT_COUNT == (1 << $clog2(POINT_COUNT)));
|
||||
end
|
||||
|
||||
/* Points coordinate RAM */
|
||||
localparam POINT_CW = $clog2(POINT_COUNT);
|
||||
localparam [7:0] V_INC = FADING == 0 ? 8'd255 : 8'('h100 / POINT_COUNT);
|
||||
|
||||
logic [23:0] pt_ram[POINT_COUNT];
|
||||
logic [POINT_CW-1:0] pt_raddr;
|
||||
logic [POINT_CW-1:0] pt_waddr;
|
||||
logic pt_wr;
|
||||
|
||||
logic [7:0] pt_xw, pt_xr;
|
||||
logic [7:0] pt_yw, pt_yr;
|
||||
logic [7:0] pt_hw, pt_hr;
|
||||
|
||||
always_ff @ (posedge clock) begin
|
||||
if (pt_wr)
|
||||
pt_ram[pt_waddr] <= {pt_hw, pt_xw, pt_yw};
|
||||
|
||||
{pt_hr, pt_xr, pt_yr} <= pt_ram[pt_raddr];
|
||||
end
|
||||
|
||||
`ifdef TESTBENCH
|
||||
integer i;
|
||||
initial
|
||||
for (i = 0; i < POINT_COUNT; i ++)
|
||||
pt_ram[i] = {8'(i*5), 8'(i*5 + 20), 8'(i*5 + 30)};
|
||||
`endif
|
||||
|
||||
/* FSM */
|
||||
enum int unsigned {
|
||||
ST_IDLE = 0, // 0
|
||||
ST_READ_LAST_PT, // 1
|
||||
ST_STORE_LAST_PT, // 2
|
||||
ST_WRITE_NEW_PT, // 3
|
||||
ST_DRAW_LAST, // 4
|
||||
ST_FIG_DRAW, // 5
|
||||
ST_NEXT_PT, // 6
|
||||
ST_READ_PT, // 7
|
||||
ST_STORE_PT, // 8
|
||||
ST_ACK // 9
|
||||
} state;
|
||||
|
||||
logic [POINT_CW-1:0] pt_last;
|
||||
|
||||
assign pt_xw = pt_x;
|
||||
assign pt_yw = pt_y;
|
||||
assign pt_hw = pt_h;
|
||||
|
||||
always_ff @ (posedge clock, posedge reset)
|
||||
if (reset) begin
|
||||
state <= ST_IDLE;
|
||||
pt_wr <= 1'b0;
|
||||
pt_last <= '0;
|
||||
pt_ack_o <= 1'b0;
|
||||
fig_req_o <= 1'b0;
|
||||
end
|
||||
else
|
||||
case (state)
|
||||
ST_IDLE: begin
|
||||
if (pt_req_i) begin
|
||||
pt_raddr <= pt_last;
|
||||
pt_waddr <= pt_last;
|
||||
pt_wr <= 1'b0;
|
||||
fig_v_o <= '0;
|
||||
state <= ST_READ_LAST_PT;
|
||||
end
|
||||
end
|
||||
|
||||
ST_READ_LAST_PT:
|
||||
state <= ST_STORE_LAST_PT;
|
||||
|
||||
ST_STORE_LAST_PT: begin
|
||||
fig_x_o <= pt_xr;
|
||||
fig_y_o <= {1'b0, pt_yr};
|
||||
fig_h_o <= pt_hr;
|
||||
fig_s_o <= 8'hff; // TODO: add saturation to ring mem
|
||||
pt_wr <= 1'b1;
|
||||
state <= ST_WRITE_NEW_PT;
|
||||
end
|
||||
|
||||
ST_WRITE_NEW_PT: begin
|
||||
pt_wr <= 1'b0;
|
||||
fig_req_o <= 1'b1;
|
||||
pt_raddr <= pt_last + 1'b1;
|
||||
state <= ST_DRAW_LAST;
|
||||
end
|
||||
|
||||
ST_DRAW_LAST:
|
||||
if (fig_ack_i) begin
|
||||
fig_req_o <= 1'b0;
|
||||
state <= ST_READ_PT;
|
||||
end
|
||||
|
||||
ST_FIG_DRAW: begin
|
||||
fig_req_o <= 1'b1;
|
||||
state <= ST_NEXT_PT;
|
||||
end
|
||||
|
||||
ST_NEXT_PT:
|
||||
if (fig_ack_i) begin
|
||||
fig_req_o <= 1'b0;
|
||||
|
||||
if (pt_raddr == pt_last) begin
|
||||
pt_last <= pt_last + 1'b1;
|
||||
pt_ack_o <= 1'b1;
|
||||
state <= ST_ACK;
|
||||
end
|
||||
else begin
|
||||
if (pt_raddr == POINT_CW'(POINT_COUNT-1))
|
||||
pt_raddr <= '0;
|
||||
else
|
||||
pt_raddr <= pt_raddr + 1'b1;
|
||||
|
||||
state <= ST_READ_PT;
|
||||
end
|
||||
end
|
||||
|
||||
ST_READ_PT:
|
||||
state <= ST_STORE_PT;
|
||||
|
||||
ST_STORE_PT: begin
|
||||
fig_x_o <= pt_xr;
|
||||
fig_y_o <= {1'b0, pt_yr};
|
||||
fig_h_o <= pt_hr;
|
||||
fig_s_o <= 8'hff; // TODO: add saturation to ring mem
|
||||
|
||||
if (fig_v_o > (255-V_INC))
|
||||
fig_v_o <= 8'hff;
|
||||
else
|
||||
fig_v_o <= fig_v_o + V_INC;
|
||||
|
||||
state <= ST_FIG_DRAW;
|
||||
end
|
||||
|
||||
ST_ACK: begin
|
||||
pt_ack_o <= 1'b0;
|
||||
state <= ST_IDLE;
|
||||
end
|
||||
endcase
|
||||
|
||||
endmodule // fig_ring
|
||||
64
source/fir-filter.m
Normal file
64
source/fir-filter.m
Normal file
@ -0,0 +1,64 @@
|
||||
pkg load signal
|
||||
|
||||
%% filter length
|
||||
flen = 511;
|
||||
|
||||
%% window
|
||||
#win = ones(flen,1);
|
||||
#win = chebwin(flen);
|
||||
#win = blackmanharris(flen);
|
||||
win = flattopwin(flen);
|
||||
|
||||
%% data width
|
||||
bits = 16;
|
||||
|
||||
%% sampling frequency
|
||||
fs = 20000
|
||||
|
||||
%% cutoff frequency
|
||||
fc = 50;
|
||||
|
||||
%% stopband frequency
|
||||
fb = 100;
|
||||
|
||||
%% amplification (dB)
|
||||
amp_db = 10;
|
||||
|
||||
%% stopband attenuation (dB)
|
||||
stop_db = -40;
|
||||
|
||||
%% filter
|
||||
amp_k = 10^(amp_db/20);
|
||||
stop_k = 10^((stop_db+amp_k)/20);
|
||||
f = [0 fc/fs fb/fs 1];
|
||||
m = [amp_k amp_k stop_k stop_k];
|
||||
fcoeff = firls(flen-1, f, m) .* win;
|
||||
|
||||
%% scale and round to 16 bit
|
||||
fcoeff_i16 = round(fcoeff .* 65536);
|
||||
|
||||
%% remove leading and trailing zeroes
|
||||
fcoeff_i16_ms = fcoeff_i16(find(fcoeff_i16,1,'first'):find(fcoeff_i16,1,'last'));
|
||||
|
||||
function ret = to_hex(x)
|
||||
if (x < 0)
|
||||
ret = 65536+x;
|
||||
else
|
||||
ret = x;
|
||||
endif
|
||||
endfunction
|
||||
|
||||
%% convert negative coeffs to 16-bit two's complement
|
||||
fcoeff_i16_hex = arrayfun(@to_hex, fcoeff_i16_ms);
|
||||
|
||||
%% printf coeffs to file
|
||||
filename = sprintf("fir_%d_%dhz_%dhz_%ddb_%ddb.rom", length(fcoeff_i16_ms), fc, fb, amp_db, -stop_db);
|
||||
printf("Write %d coefficients to file %s\n", length(fcoeff_i16_ms), filename);
|
||||
|
||||
file = fopen(filename, "w");
|
||||
fprintf(file, "%04x\n", fcoeff_i16_hex);
|
||||
fclose(file);
|
||||
|
||||
%% make real coeffs for freqz
|
||||
fcoeff_i = fcoeff_i16_ms ./ 65536;
|
||||
freqz(fcoeff_i);
|
||||
363
source/fir_363_250hz_400hz_0db_40db.rom
Normal file
363
source/fir_363_250hz_400hz_0db_40db.rom
Normal file
@ -0,0 +1,363 @@
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
0000
|
||||
0000
|
||||
0000
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0000
|
||||
0000
|
||||
ffff
|
||||
ffff
|
||||
fffe
|
||||
fffd
|
||||
fffd
|
||||
fffc
|
||||
fffb
|
||||
fff9
|
||||
fff8
|
||||
fff7
|
||||
fff5
|
||||
fff4
|
||||
fff2
|
||||
fff1
|
||||
ffef
|
||||
ffed
|
||||
ffeb
|
||||
ffe9
|
||||
ffe7
|
||||
ffe6
|
||||
ffe4
|
||||
ffe2
|
||||
ffe0
|
||||
ffde
|
||||
ffdc
|
||||
ffda
|
||||
ffd9
|
||||
ffd7
|
||||
ffd6
|
||||
ffd5
|
||||
ffd4
|
||||
ffd3
|
||||
ffd2
|
||||
ffd2
|
||||
ffd2
|
||||
ffd2
|
||||
ffd3
|
||||
ffd4
|
||||
ffd6
|
||||
ffd8
|
||||
ffda
|
||||
ffdd
|
||||
ffe0
|
||||
ffe4
|
||||
ffe9
|
||||
ffee
|
||||
fff3
|
||||
fff9
|
||||
0000
|
||||
0008
|
||||
0010
|
||||
0019
|
||||
0023
|
||||
002d
|
||||
0038
|
||||
0044
|
||||
0051
|
||||
005e
|
||||
006c
|
||||
007b
|
||||
008b
|
||||
009b
|
||||
00ac
|
||||
00be
|
||||
00d0
|
||||
00e3
|
||||
00f7
|
||||
010b
|
||||
0120
|
||||
0136
|
||||
014c
|
||||
0162
|
||||
0179
|
||||
0190
|
||||
01a8
|
||||
01c0
|
||||
01d8
|
||||
01f1
|
||||
0209
|
||||
0222
|
||||
023b
|
||||
0253
|
||||
026c
|
||||
0284
|
||||
029c
|
||||
02b4
|
||||
02cc
|
||||
02e3
|
||||
02fa
|
||||
0311
|
||||
0326
|
||||
033b
|
||||
0350
|
||||
0364
|
||||
0377
|
||||
0389
|
||||
039a
|
||||
03aa
|
||||
03b9
|
||||
03c7
|
||||
03d4
|
||||
03e0
|
||||
03eb
|
||||
03f5
|
||||
03fd
|
||||
0404
|
||||
040a
|
||||
040f
|
||||
0412
|
||||
0414
|
||||
06f4
|
||||
0414
|
||||
0412
|
||||
040f
|
||||
040a
|
||||
0404
|
||||
03fd
|
||||
03f5
|
||||
03eb
|
||||
03e0
|
||||
03d4
|
||||
03c7
|
||||
03b9
|
||||
03aa
|
||||
039a
|
||||
0389
|
||||
0377
|
||||
0364
|
||||
0350
|
||||
033b
|
||||
0326
|
||||
0311
|
||||
02fa
|
||||
02e3
|
||||
02cc
|
||||
02b4
|
||||
029c
|
||||
0284
|
||||
026c
|
||||
0253
|
||||
023b
|
||||
0222
|
||||
0209
|
||||
01f1
|
||||
01d8
|
||||
01c0
|
||||
01a8
|
||||
0190
|
||||
0179
|
||||
0162
|
||||
014c
|
||||
0136
|
||||
0120
|
||||
010b
|
||||
00f7
|
||||
00e3
|
||||
00d0
|
||||
00be
|
||||
00ac
|
||||
009b
|
||||
008b
|
||||
007b
|
||||
006c
|
||||
005e
|
||||
0051
|
||||
0044
|
||||
0038
|
||||
002d
|
||||
0023
|
||||
0019
|
||||
0010
|
||||
0008
|
||||
0000
|
||||
fff9
|
||||
fff3
|
||||
ffee
|
||||
ffe9
|
||||
ffe4
|
||||
ffe0
|
||||
ffdd
|
||||
ffda
|
||||
ffd8
|
||||
ffd6
|
||||
ffd4
|
||||
ffd3
|
||||
ffd2
|
||||
ffd2
|
||||
ffd2
|
||||
ffd2
|
||||
ffd3
|
||||
ffd4
|
||||
ffd5
|
||||
ffd6
|
||||
ffd7
|
||||
ffd9
|
||||
ffda
|
||||
ffdc
|
||||
ffde
|
||||
ffe0
|
||||
ffe2
|
||||
ffe4
|
||||
ffe6
|
||||
ffe7
|
||||
ffe9
|
||||
ffeb
|
||||
ffed
|
||||
ffef
|
||||
fff1
|
||||
fff2
|
||||
fff4
|
||||
fff5
|
||||
fff7
|
||||
fff8
|
||||
fff9
|
||||
fffb
|
||||
fffc
|
||||
fffd
|
||||
fffd
|
||||
fffe
|
||||
ffff
|
||||
ffff
|
||||
0000
|
||||
0000
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0001
|
||||
0000
|
||||
0000
|
||||
0000
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
425
source/fir_425_50hz_100hz_0db_40db.rom
Normal file
425
source/fir_425_50hz_100hz_0db_40db.rom
Normal file
@ -0,0 +1,425 @@
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fff9
|
||||
fff9
|
||||
fff9
|
||||
fff9
|
||||
fff9
|
||||
fff9
|
||||
fff8
|
||||
fff8
|
||||
fff8
|
||||
fff8
|
||||
fff8
|
||||
fff8
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff8
|
||||
fff8
|
||||
fff8
|
||||
fff8
|
||||
fff9
|
||||
fff9
|
||||
fff9
|
||||
fffa
|
||||
fffa
|
||||
fffb
|
||||
fffb
|
||||
fffc
|
||||
fffd
|
||||
fffd
|
||||
fffe
|
||||
ffff
|
||||
ffff
|
||||
0000
|
||||
0001
|
||||
0002
|
||||
0003
|
||||
0004
|
||||
0005
|
||||
0006
|
||||
0007
|
||||
0008
|
||||
0009
|
||||
000b
|
||||
000c
|
||||
000d
|
||||
000f
|
||||
0010
|
||||
0012
|
||||
0013
|
||||
0015
|
||||
0017
|
||||
0018
|
||||
001a
|
||||
001c
|
||||
001e
|
||||
0020
|
||||
0022
|
||||
0024
|
||||
0026
|
||||
0028
|
||||
002a
|
||||
002d
|
||||
002f
|
||||
0031
|
||||
0034
|
||||
0036
|
||||
0039
|
||||
003b
|
||||
003e
|
||||
0040
|
||||
0043
|
||||
0046
|
||||
0048
|
||||
004b
|
||||
004e
|
||||
0051
|
||||
0054
|
||||
0057
|
||||
0059
|
||||
005c
|
||||
005f
|
||||
0062
|
||||
0065
|
||||
0068
|
||||
006c
|
||||
006f
|
||||
0072
|
||||
0075
|
||||
0078
|
||||
007b
|
||||
007e
|
||||
0081
|
||||
0084
|
||||
0088
|
||||
008b
|
||||
008e
|
||||
0091
|
||||
0094
|
||||
0097
|
||||
009a
|
||||
009d
|
||||
00a0
|
||||
00a3
|
||||
00a6
|
||||
00a9
|
||||
00ac
|
||||
00af
|
||||
00b2
|
||||
00b4
|
||||
00b7
|
||||
00ba
|
||||
00bc
|
||||
00bf
|
||||
00c1
|
||||
00c4
|
||||
00c6
|
||||
00c9
|
||||
00cb
|
||||
00cd
|
||||
00cf
|
||||
00d1
|
||||
00d3
|
||||
00d5
|
||||
00d7
|
||||
00d9
|
||||
00db
|
||||
00dc
|
||||
00de
|
||||
00df
|
||||
00e1
|
||||
00e2
|
||||
00e3
|
||||
00e4
|
||||
00e5
|
||||
00e6
|
||||
00e7
|
||||
00e8
|
||||
00e8
|
||||
00e9
|
||||
00e9
|
||||
00e9
|
||||
00ea
|
||||
00ea
|
||||
03c9
|
||||
00ea
|
||||
00ea
|
||||
00e9
|
||||
00e9
|
||||
00e9
|
||||
00e8
|
||||
00e8
|
||||
00e7
|
||||
00e6
|
||||
00e5
|
||||
00e4
|
||||
00e3
|
||||
00e2
|
||||
00e1
|
||||
00df
|
||||
00de
|
||||
00dc
|
||||
00db
|
||||
00d9
|
||||
00d7
|
||||
00d5
|
||||
00d3
|
||||
00d1
|
||||
00cf
|
||||
00cd
|
||||
00cb
|
||||
00c9
|
||||
00c6
|
||||
00c4
|
||||
00c1
|
||||
00bf
|
||||
00bc
|
||||
00ba
|
||||
00b7
|
||||
00b4
|
||||
00b2
|
||||
00af
|
||||
00ac
|
||||
00a9
|
||||
00a6
|
||||
00a3
|
||||
00a0
|
||||
009d
|
||||
009a
|
||||
0097
|
||||
0094
|
||||
0091
|
||||
008e
|
||||
008b
|
||||
0088
|
||||
0084
|
||||
0081
|
||||
007e
|
||||
007b
|
||||
0078
|
||||
0075
|
||||
0072
|
||||
006f
|
||||
006c
|
||||
0068
|
||||
0065
|
||||
0062
|
||||
005f
|
||||
005c
|
||||
0059
|
||||
0057
|
||||
0054
|
||||
0051
|
||||
004e
|
||||
004b
|
||||
0048
|
||||
0046
|
||||
0043
|
||||
0040
|
||||
003e
|
||||
003b
|
||||
0039
|
||||
0036
|
||||
0034
|
||||
0031
|
||||
002f
|
||||
002d
|
||||
002a
|
||||
0028
|
||||
0026
|
||||
0024
|
||||
0022
|
||||
0020
|
||||
001e
|
||||
001c
|
||||
001a
|
||||
0018
|
||||
0017
|
||||
0015
|
||||
0013
|
||||
0012
|
||||
0010
|
||||
000f
|
||||
000d
|
||||
000c
|
||||
000b
|
||||
0009
|
||||
0008
|
||||
0007
|
||||
0006
|
||||
0005
|
||||
0004
|
||||
0003
|
||||
0002
|
||||
0001
|
||||
0000
|
||||
ffff
|
||||
ffff
|
||||
fffe
|
||||
fffd
|
||||
fffd
|
||||
fffc
|
||||
fffb
|
||||
fffb
|
||||
fffa
|
||||
fffa
|
||||
fff9
|
||||
fff9
|
||||
fff9
|
||||
fff8
|
||||
fff8
|
||||
fff8
|
||||
fff8
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff7
|
||||
fff8
|
||||
fff8
|
||||
fff8
|
||||
fff8
|
||||
fff8
|
||||
fff8
|
||||
fff9
|
||||
fff9
|
||||
fff9
|
||||
fff9
|
||||
fff9
|
||||
fff9
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
449
source/fir_449_50hz_100hz_10db_40db.rom
Normal file
449
source/fir_449_50hz_100hz_10db_40db.rom
Normal file
@ -0,0 +1,449 @@
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fff9
|
||||
fff9
|
||||
fff8
|
||||
fff8
|
||||
fff8
|
||||
fff7
|
||||
fff7
|
||||
fff6
|
||||
fff6
|
||||
fff6
|
||||
fff5
|
||||
fff5
|
||||
fff4
|
||||
fff4
|
||||
fff3
|
||||
fff3
|
||||
fff2
|
||||
fff1
|
||||
fff1
|
||||
fff0
|
||||
fff0
|
||||
ffef
|
||||
ffef
|
||||
ffee
|
||||
ffed
|
||||
ffed
|
||||
ffec
|
||||
ffec
|
||||
ffeb
|
||||
ffeb
|
||||
ffea
|
||||
ffe9
|
||||
ffe9
|
||||
ffe8
|
||||
ffe8
|
||||
ffe7
|
||||
ffe7
|
||||
ffe6
|
||||
ffe6
|
||||
ffe5
|
||||
ffe5
|
||||
ffe4
|
||||
ffe4
|
||||
ffe4
|
||||
ffe3
|
||||
ffe3
|
||||
ffe3
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe3
|
||||
ffe3
|
||||
ffe4
|
||||
ffe4
|
||||
ffe5
|
||||
ffe5
|
||||
ffe6
|
||||
ffe7
|
||||
ffe8
|
||||
ffe9
|
||||
ffea
|
||||
ffeb
|
||||
ffed
|
||||
ffee
|
||||
fff0
|
||||
fff1
|
||||
fff3
|
||||
fff5
|
||||
fff7
|
||||
fff9
|
||||
fffc
|
||||
fffe
|
||||
0001
|
||||
0003
|
||||
0006
|
||||
0009
|
||||
000c
|
||||
000f
|
||||
0013
|
||||
0016
|
||||
001a
|
||||
001e
|
||||
0022
|
||||
0026
|
||||
002b
|
||||
002f
|
||||
0034
|
||||
0039
|
||||
003e
|
||||
0043
|
||||
0048
|
||||
004e
|
||||
0054
|
||||
0059
|
||||
005f
|
||||
0066
|
||||
006c
|
||||
0072
|
||||
0079
|
||||
0080
|
||||
0087
|
||||
008e
|
||||
0095
|
||||
009d
|
||||
00a4
|
||||
00ac
|
||||
00b4
|
||||
00bc
|
||||
00c4
|
||||
00cd
|
||||
00d5
|
||||
00de
|
||||
00e6
|
||||
00ef
|
||||
00f8
|
||||
0101
|
||||
010a
|
||||
0113
|
||||
011d
|
||||
0126
|
||||
0130
|
||||
0139
|
||||
0143
|
||||
014d
|
||||
0156
|
||||
0160
|
||||
016a
|
||||
0174
|
||||
017e
|
||||
0188
|
||||
0192
|
||||
019c
|
||||
01a6
|
||||
01b0
|
||||
01ba
|
||||
01c3
|
||||
01cd
|
||||
01d7
|
||||
01e1
|
||||
01eb
|
||||
01f4
|
||||
01fe
|
||||
0207
|
||||
0211
|
||||
021a
|
||||
0223
|
||||
022c
|
||||
0235
|
||||
023e
|
||||
0247
|
||||
024f
|
||||
0258
|
||||
0260
|
||||
0268
|
||||
0270
|
||||
0277
|
||||
027f
|
||||
0286
|
||||
028d
|
||||
0294
|
||||
029a
|
||||
02a1
|
||||
02a7
|
||||
02ad
|
||||
02b3
|
||||
02b8
|
||||
02bd
|
||||
02c2
|
||||
02c7
|
||||
02cb
|
||||
02cf
|
||||
02d3
|
||||
02d6
|
||||
02d9
|
||||
02dc
|
||||
02df
|
||||
02e1
|
||||
02e3
|
||||
02e5
|
||||
02e6
|
||||
02e7
|
||||
02e8
|
||||
02e8
|
||||
0698
|
||||
02e8
|
||||
02e8
|
||||
02e7
|
||||
02e6
|
||||
02e5
|
||||
02e3
|
||||
02e1
|
||||
02df
|
||||
02dc
|
||||
02d9
|
||||
02d6
|
||||
02d3
|
||||
02cf
|
||||
02cb
|
||||
02c7
|
||||
02c2
|
||||
02bd
|
||||
02b8
|
||||
02b3
|
||||
02ad
|
||||
02a7
|
||||
02a1
|
||||
029a
|
||||
0294
|
||||
028d
|
||||
0286
|
||||
027f
|
||||
0277
|
||||
0270
|
||||
0268
|
||||
0260
|
||||
0258
|
||||
024f
|
||||
0247
|
||||
023e
|
||||
0235
|
||||
022c
|
||||
0223
|
||||
021a
|
||||
0211
|
||||
0207
|
||||
01fe
|
||||
01f4
|
||||
01eb
|
||||
01e1
|
||||
01d7
|
||||
01cd
|
||||
01c3
|
||||
01ba
|
||||
01b0
|
||||
01a6
|
||||
019c
|
||||
0192
|
||||
0188
|
||||
017e
|
||||
0174
|
||||
016a
|
||||
0160
|
||||
0156
|
||||
014d
|
||||
0143
|
||||
0139
|
||||
0130
|
||||
0126
|
||||
011d
|
||||
0113
|
||||
010a
|
||||
0101
|
||||
00f8
|
||||
00ef
|
||||
00e6
|
||||
00de
|
||||
00d5
|
||||
00cd
|
||||
00c4
|
||||
00bc
|
||||
00b4
|
||||
00ac
|
||||
00a4
|
||||
009d
|
||||
0095
|
||||
008e
|
||||
0087
|
||||
0080
|
||||
0079
|
||||
0072
|
||||
006c
|
||||
0066
|
||||
005f
|
||||
0059
|
||||
0054
|
||||
004e
|
||||
0048
|
||||
0043
|
||||
003e
|
||||
0039
|
||||
0034
|
||||
002f
|
||||
002b
|
||||
0026
|
||||
0022
|
||||
001e
|
||||
001a
|
||||
0016
|
||||
0013
|
||||
000f
|
||||
000c
|
||||
0009
|
||||
0006
|
||||
0003
|
||||
0001
|
||||
fffe
|
||||
fffc
|
||||
fff9
|
||||
fff7
|
||||
fff5
|
||||
fff3
|
||||
fff1
|
||||
fff0
|
||||
ffee
|
||||
ffed
|
||||
ffeb
|
||||
ffea
|
||||
ffe9
|
||||
ffe8
|
||||
ffe7
|
||||
ffe6
|
||||
ffe5
|
||||
ffe5
|
||||
ffe4
|
||||
ffe4
|
||||
ffe3
|
||||
ffe3
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe2
|
||||
ffe3
|
||||
ffe3
|
||||
ffe3
|
||||
ffe4
|
||||
ffe4
|
||||
ffe4
|
||||
ffe5
|
||||
ffe5
|
||||
ffe6
|
||||
ffe6
|
||||
ffe7
|
||||
ffe7
|
||||
ffe8
|
||||
ffe8
|
||||
ffe9
|
||||
ffe9
|
||||
ffea
|
||||
ffeb
|
||||
ffeb
|
||||
ffec
|
||||
ffec
|
||||
ffed
|
||||
ffed
|
||||
ffee
|
||||
ffef
|
||||
ffef
|
||||
fff0
|
||||
fff0
|
||||
fff1
|
||||
fff1
|
||||
fff2
|
||||
fff3
|
||||
fff3
|
||||
fff4
|
||||
fff4
|
||||
fff5
|
||||
fff5
|
||||
fff6
|
||||
fff6
|
||||
fff6
|
||||
fff7
|
||||
fff7
|
||||
fff8
|
||||
fff8
|
||||
fff8
|
||||
fff9
|
||||
fff9
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffb
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
465
source/fir_465_50hz_100hz_20db_40db.rom
Normal file
465
source/fir_465_50hz_100hz_20db_40db.rom
Normal file
@ -0,0 +1,465 @@
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffb
|
||||
fffb
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fff9
|
||||
fff9
|
||||
fff8
|
||||
fff7
|
||||
fff7
|
||||
fff6
|
||||
fff5
|
||||
fff5
|
||||
fff4
|
||||
fff3
|
||||
fff2
|
||||
fff2
|
||||
fff1
|
||||
fff0
|
||||
ffef
|
||||
ffee
|
||||
ffed
|
||||
ffec
|
||||
ffeb
|
||||
ffe9
|
||||
ffe8
|
||||
ffe7
|
||||
ffe6
|
||||
ffe4
|
||||
ffe3
|
||||
ffe2
|
||||
ffe0
|
||||
ffdf
|
||||
ffdd
|
||||
ffdc
|
||||
ffda
|
||||
ffd9
|
||||
ffd7
|
||||
ffd5
|
||||
ffd4
|
||||
ffd2
|
||||
ffd0
|
||||
ffce
|
||||
ffcd
|
||||
ffcb
|
||||
ffc9
|
||||
ffc7
|
||||
ffc5
|
||||
ffc3
|
||||
ffc2
|
||||
ffc0
|
||||
ffbe
|
||||
ffbc
|
||||
ffba
|
||||
ffb8
|
||||
ffb6
|
||||
ffb5
|
||||
ffb3
|
||||
ffb1
|
||||
ffb0
|
||||
ffae
|
||||
ffac
|
||||
ffab
|
||||
ffaa
|
||||
ffa8
|
||||
ffa7
|
||||
ffa6
|
||||
ffa5
|
||||
ffa4
|
||||
ffa3
|
||||
ffa2
|
||||
ffa2
|
||||
ffa1
|
||||
ffa1
|
||||
ffa1
|
||||
ffa1
|
||||
ffa1
|
||||
ffa1
|
||||
ffa2
|
||||
ffa2
|
||||
ffa3
|
||||
ffa4
|
||||
ffa6
|
||||
ffa7
|
||||
ffa9
|
||||
ffab
|
||||
ffae
|
||||
ffb1
|
||||
ffb4
|
||||
ffb7
|
||||
ffba
|
||||
ffbe
|
||||
ffc3
|
||||
ffc7
|
||||
ffcc
|
||||
ffd2
|
||||
ffd7
|
||||
ffdd
|
||||
ffe4
|
||||
ffeb
|
||||
fff2
|
||||
fffa
|
||||
0002
|
||||
000a
|
||||
0013
|
||||
001d
|
||||
0027
|
||||
0031
|
||||
003c
|
||||
0047
|
||||
0053
|
||||
005f
|
||||
006c
|
||||
007a
|
||||
0087
|
||||
0096
|
||||
00a5
|
||||
00b4
|
||||
00c4
|
||||
00d4
|
||||
00e5
|
||||
00f7
|
||||
0109
|
||||
011b
|
||||
012e
|
||||
0142
|
||||
0156
|
||||
016a
|
||||
0180
|
||||
0195
|
||||
01ab
|
||||
01c2
|
||||
01d9
|
||||
01f1
|
||||
0209
|
||||
0221
|
||||
023a
|
||||
0254
|
||||
026e
|
||||
0288
|
||||
02a3
|
||||
02be
|
||||
02d9
|
||||
02f5
|
||||
0312
|
||||
032e
|
||||
034b
|
||||
0368
|
||||
0386
|
||||
03a4
|
||||
03c2
|
||||
03e0
|
||||
03ff
|
||||
041d
|
||||
043c
|
||||
045b
|
||||
047b
|
||||
049a
|
||||
04b9
|
||||
04d9
|
||||
04f8
|
||||
0518
|
||||
0537
|
||||
0557
|
||||
0576
|
||||
0596
|
||||
05b5
|
||||
05d4
|
||||
05f3
|
||||
0612
|
||||
0630
|
||||
064f
|
||||
066d
|
||||
068a
|
||||
06a8
|
||||
06c5
|
||||
06e2
|
||||
06fe
|
||||
071a
|
||||
0735
|
||||
0750
|
||||
076b
|
||||
0785
|
||||
079e
|
||||
07b7
|
||||
07cf
|
||||
07e7
|
||||
07fe
|
||||
0814
|
||||
082a
|
||||
083f
|
||||
0853
|
||||
0866
|
||||
0879
|
||||
088b
|
||||
089c
|
||||
08ac
|
||||
08bb
|
||||
08ca
|
||||
08d8
|
||||
08e4
|
||||
08f0
|
||||
08fb
|
||||
0905
|
||||
090f
|
||||
0917
|
||||
091e
|
||||
0924
|
||||
092a
|
||||
092e
|
||||
0932
|
||||
0934
|
||||
0935
|
||||
114e
|
||||
0935
|
||||
0934
|
||||
0932
|
||||
092e
|
||||
092a
|
||||
0924
|
||||
091e
|
||||
0917
|
||||
090f
|
||||
0905
|
||||
08fb
|
||||
08f0
|
||||
08e4
|
||||
08d8
|
||||
08ca
|
||||
08bb
|
||||
08ac
|
||||
089c
|
||||
088b
|
||||
0879
|
||||
0866
|
||||
0853
|
||||
083f
|
||||
082a
|
||||
0814
|
||||
07fe
|
||||
07e7
|
||||
07cf
|
||||
07b7
|
||||
079e
|
||||
0785
|
||||
076b
|
||||
0750
|
||||
0735
|
||||
071a
|
||||
06fe
|
||||
06e2
|
||||
06c5
|
||||
06a8
|
||||
068a
|
||||
066d
|
||||
064f
|
||||
0630
|
||||
0612
|
||||
05f3
|
||||
05d4
|
||||
05b5
|
||||
0596
|
||||
0576
|
||||
0557
|
||||
0537
|
||||
0518
|
||||
04f8
|
||||
04d9
|
||||
04b9
|
||||
049a
|
||||
047b
|
||||
045b
|
||||
043c
|
||||
041d
|
||||
03ff
|
||||
03e0
|
||||
03c2
|
||||
03a4
|
||||
0386
|
||||
0368
|
||||
034b
|
||||
032e
|
||||
0312
|
||||
02f5
|
||||
02d9
|
||||
02be
|
||||
02a3
|
||||
0288
|
||||
026e
|
||||
0254
|
||||
023a
|
||||
0221
|
||||
0209
|
||||
01f1
|
||||
01d9
|
||||
01c2
|
||||
01ab
|
||||
0195
|
||||
0180
|
||||
016a
|
||||
0156
|
||||
0142
|
||||
012e
|
||||
011b
|
||||
0109
|
||||
00f7
|
||||
00e5
|
||||
00d4
|
||||
00c4
|
||||
00b4
|
||||
00a5
|
||||
0096
|
||||
0087
|
||||
007a
|
||||
006c
|
||||
005f
|
||||
0053
|
||||
0047
|
||||
003c
|
||||
0031
|
||||
0027
|
||||
001d
|
||||
0013
|
||||
000a
|
||||
0002
|
||||
fffa
|
||||
fff2
|
||||
ffeb
|
||||
ffe4
|
||||
ffdd
|
||||
ffd7
|
||||
ffd2
|
||||
ffcc
|
||||
ffc7
|
||||
ffc3
|
||||
ffbe
|
||||
ffba
|
||||
ffb7
|
||||
ffb4
|
||||
ffb1
|
||||
ffae
|
||||
ffab
|
||||
ffa9
|
||||
ffa7
|
||||
ffa6
|
||||
ffa4
|
||||
ffa3
|
||||
ffa2
|
||||
ffa2
|
||||
ffa1
|
||||
ffa1
|
||||
ffa1
|
||||
ffa1
|
||||
ffa1
|
||||
ffa1
|
||||
ffa2
|
||||
ffa2
|
||||
ffa3
|
||||
ffa4
|
||||
ffa5
|
||||
ffa6
|
||||
ffa7
|
||||
ffa8
|
||||
ffaa
|
||||
ffab
|
||||
ffac
|
||||
ffae
|
||||
ffb0
|
||||
ffb1
|
||||
ffb3
|
||||
ffb5
|
||||
ffb6
|
||||
ffb8
|
||||
ffba
|
||||
ffbc
|
||||
ffbe
|
||||
ffc0
|
||||
ffc2
|
||||
ffc3
|
||||
ffc5
|
||||
ffc7
|
||||
ffc9
|
||||
ffcb
|
||||
ffcd
|
||||
ffce
|
||||
ffd0
|
||||
ffd2
|
||||
ffd4
|
||||
ffd5
|
||||
ffd7
|
||||
ffd9
|
||||
ffda
|
||||
ffdc
|
||||
ffdd
|
||||
ffdf
|
||||
ffe0
|
||||
ffe2
|
||||
ffe3
|
||||
ffe4
|
||||
ffe6
|
||||
ffe7
|
||||
ffe8
|
||||
ffe9
|
||||
ffeb
|
||||
ffec
|
||||
ffed
|
||||
ffee
|
||||
ffef
|
||||
fff0
|
||||
fff1
|
||||
fff2
|
||||
fff2
|
||||
fff3
|
||||
fff4
|
||||
fff5
|
||||
fff5
|
||||
fff6
|
||||
fff7
|
||||
fff7
|
||||
fff8
|
||||
fff9
|
||||
fff9
|
||||
fffa
|
||||
fffa
|
||||
fffa
|
||||
fffb
|
||||
fffb
|
||||
fffc
|
||||
fffc
|
||||
fffc
|
||||
fffd
|
||||
fffd
|
||||
fffd
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
fffe
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
ffff
|
||||
123
source/fir_filter.sv
Normal file
123
source/fir_filter.sv
Normal file
@ -0,0 +1,123 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
|
||||
module fir_filter #(parameter LEN = 449,
|
||||
parameter COEFFS_ROM_FILE = "fir_449_50hz_100hz_10db_40db.rom")
|
||||
(input wire clock,
|
||||
input wire reset,
|
||||
|
||||
input wire signed [15:0] data_i,
|
||||
input wire ready_i,
|
||||
|
||||
output wire signed [15:0] data_o,
|
||||
output reg valid_o);
|
||||
|
||||
localparam LEN_CW = $clog2(LEN);
|
||||
localparam MEM_LEN = 1 << LEN_CW;
|
||||
|
||||
/* Coeffs */
|
||||
logic signed [15:0] coeffs[LEN];
|
||||
initial $readmemh(COEFFS_ROM_FILE, coeffs, 0, LEN-1);
|
||||
|
||||
logic signed [15:0] coeff;
|
||||
logic [LEN_CW-1:0] coeff_addr;
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
coeff <= coeffs[coeff_addr];
|
||||
|
||||
/* Z-1 BlockRAM */
|
||||
logic signed [15:0] mem[MEM_LEN];
|
||||
logic signed [15:0] mem_wdata;
|
||||
logic signed [15:0] mem_rdata;
|
||||
logic [LEN_CW-1:0] mem_addr;
|
||||
logic mem_wr;
|
||||
|
||||
always_ff @ (posedge clock) begin
|
||||
if (mem_wr)
|
||||
mem[mem_addr] <= mem_wdata;
|
||||
mem_rdata <= mem[mem_addr];
|
||||
end
|
||||
|
||||
initial begin
|
||||
integer i;
|
||||
for (i = 0; i < MEM_LEN; i++)
|
||||
mem[i] = '0;
|
||||
end
|
||||
|
||||
/* MAC */
|
||||
logic [31:0] mac_o;
|
||||
logic signed [15:0] a;
|
||||
logic signed [15:0] b;
|
||||
logic signed [15:0] s;
|
||||
|
||||
ice40_mac16x16 #(.SIGNED(1)) mac
|
||||
(.clock, .reset,
|
||||
.a(a),
|
||||
.b(b),
|
||||
.s({s, 16'b0}),
|
||||
.sub(1'b0),
|
||||
.y(mac_o));
|
||||
|
||||
/* FSM */
|
||||
enum int unsigned {
|
||||
ST_IDLE = 0,
|
||||
ST_WRITE,
|
||||
ST_CONV,
|
||||
ST_DONE
|
||||
} state;
|
||||
|
||||
logic [LEN_CW-1:0] new_addr;
|
||||
|
||||
assign mem_wdata = data_i;
|
||||
assign data_o = s;
|
||||
assign s = coeff_addr == '0 ? '0 : mac_o[31:16];
|
||||
|
||||
always_ff @ (posedge clock, posedge reset)
|
||||
if (reset) begin
|
||||
state <= ST_IDLE;
|
||||
new_addr <= '0;
|
||||
mem_wr <= 1'b0;
|
||||
valid_o <= 1'b0;
|
||||
end
|
||||
else
|
||||
case (state)
|
||||
ST_IDLE: begin
|
||||
a <= '0;
|
||||
b <= '0;
|
||||
mem_addr <= new_addr;
|
||||
coeff_addr <= '0;
|
||||
|
||||
if (ready_i) begin
|
||||
mem_wr <= 1'b1;
|
||||
state <= ST_WRITE;
|
||||
end
|
||||
end
|
||||
|
||||
ST_WRITE: begin
|
||||
mem_wr <= 1'b0;
|
||||
state <= ST_CONV;
|
||||
end
|
||||
|
||||
ST_CONV: begin
|
||||
a <= mem_rdata;
|
||||
b <= coeff;
|
||||
|
||||
if (coeff_addr == LEN_CW'(LEN-1)) begin
|
||||
valid_o <= 1'b1;
|
||||
state <= ST_DONE;
|
||||
end
|
||||
else begin
|
||||
coeff_addr <= coeff_addr + 1'b1;
|
||||
mem_addr <= mem_addr - 1'b1;
|
||||
state <= ST_CONV;
|
||||
end
|
||||
end
|
||||
|
||||
ST_DONE: begin
|
||||
new_addr <= new_addr + 1'b1;
|
||||
valid_o <= 1'b0;
|
||||
state <= ST_IDLE;
|
||||
end
|
||||
endcase
|
||||
|
||||
endmodule // fir_filter
|
||||
239
source/hsl2rgb.sv
Normal file
239
source/hsl2rgb.sv
Normal file
@ -0,0 +1,239 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
|
||||
/**
|
||||
* HSL to RGB translation.
|
||||
*
|
||||
* H, S, L = [0..1)
|
||||
*
|
||||
* Q = | L < 0.5 ? L + L*S
|
||||
* | L >= 0.5 ? L + S - L*S
|
||||
*
|
||||
* P = 2 * L - Q
|
||||
*
|
||||
* TR = H < 2/3 ? H + 1/3 : 1/3 - (1 - H)
|
||||
* TG = H
|
||||
* TB = H >= 1/3 ? H - 1/3 : 1 - H
|
||||
*
|
||||
* COLORX = | TX < 1/6 ? P + ((Q - P) * 6 * TX)
|
||||
* | 1/6 <= TX < 1/2 ? Q
|
||||
* | 1/2 <= TX < 2/3 ? P + ((Q - P) * (2/3 - TX) * 6)
|
||||
* | else : P
|
||||
*/
|
||||
|
||||
/*
|
||||
* Datapath:
|
||||
*
|
||||
* if l < [1/2]
|
||||
* then: lls = l + (l * s)
|
||||
* else: lls = l - (l * s)
|
||||
*
|
||||
* m1h = ~(h - 1)
|
||||
*
|
||||
* tr =
|
||||
* if h < [2/3]
|
||||
* then: h + [1/3]
|
||||
* else: [1/3] - m1h
|
||||
*
|
||||
* tg = h
|
||||
*
|
||||
* tb =
|
||||
* if h >= [1/3]
|
||||
* then: h - [1/3]
|
||||
* else: m1h
|
||||
*
|
||||
* q =
|
||||
* if l < [1/2]
|
||||
* then: lls
|
||||
* else: lls + s
|
||||
*
|
||||
* p = l * 2 - q
|
||||
* qp = (q - l) * 2
|
||||
*
|
||||
* r =
|
||||
* p + 6 * qp * tr
|
||||
* p + 6 * qp * ([2/3] - tr)
|
||||
*
|
||||
* g =
|
||||
* p + 6 * qp * tg
|
||||
* p + 6 * qp * ([2/3] - tg)
|
||||
*
|
||||
* b =
|
||||
* p + 6 * qp * tb
|
||||
* p + 6 * qp * ([2/3] - tb)
|
||||
*/
|
||||
|
||||
module hsl2rgb
|
||||
(input wire clock,
|
||||
input wire reset,
|
||||
|
||||
input wire [7:0] h,
|
||||
input wire [7:0] s,
|
||||
input wire [7:0] l,
|
||||
input wire ready_i,
|
||||
|
||||
output reg [7:0] r,
|
||||
output reg [7:0] g,
|
||||
output reg [7:0] b,
|
||||
output wire valid_o);
|
||||
|
||||
`define C1_6 43
|
||||
`define C1_3 85
|
||||
`define C1_2 128
|
||||
`define C2_3 171
|
||||
`define C1_1 256
|
||||
|
||||
localparam STAGES = 5;
|
||||
logic [STAGES-1:0] valid;
|
||||
|
||||
assign valid_o = valid[STAGES-1];
|
||||
|
||||
always_ff @ (posedge clock, posedge reset)
|
||||
if (reset)
|
||||
valid <= '0;
|
||||
else
|
||||
valid <= { valid[STAGES-2:0], ready_i };
|
||||
|
||||
/* ---------------- Stage 1 ---------------- */
|
||||
logic [8:0] lls; // lls = l0 ± (l0 * s0)
|
||||
logic ls_sub;
|
||||
|
||||
/* verilator lint_off UNUSED */
|
||||
logic [31:0] mac_lls_o;
|
||||
/* verilator lint_on UNUSED */
|
||||
|
||||
assign lls = {mac_lls_o[16:8]};
|
||||
assign ls_sub = l < `C1_2 ? 1'b0 : 1'b1;
|
||||
|
||||
ice40_mac16x16 mac_lls
|
||||
(.clock, .reset,
|
||||
.a({8'b0, l}),
|
||||
.b({8'b0, s}),
|
||||
.s({16'b0, l, 8'b0}),
|
||||
.sub(ls_sub),
|
||||
.y(mac_lls_o));
|
||||
|
||||
/* propagate to next stage */
|
||||
logic [7:0] h1, s1, l1;
|
||||
always_ff @ (posedge clock) begin
|
||||
h1 <= h;
|
||||
s1 <= s;
|
||||
l1 <= l;
|
||||
end
|
||||
|
||||
/* ---------------- stage 2 ---------------- */
|
||||
logic [8:0] q_pre;
|
||||
logic [7:0] q;
|
||||
logic [7:0] minus1h; // minus1h = 256 - h = ~(h - 1)
|
||||
|
||||
always_ff @ (posedge clock) begin
|
||||
q_pre <= l1 < `C1_2 ? lls : lls + s1;
|
||||
minus1h <= ~(h1 - 1);
|
||||
end
|
||||
|
||||
assign q = q_pre[8] ? 8'hff : q_pre[7:0];
|
||||
|
||||
/* propagate to next stage */
|
||||
logic [7:0] h2, l2;
|
||||
always_ff @ (posedge clock) begin
|
||||
h2 <= h1;
|
||||
l2 <= l1;
|
||||
end
|
||||
|
||||
/* ---------------- stage 3 ---------------- */
|
||||
logic [7:0] tr, tg, tb;
|
||||
logic [8:0] p_pre;
|
||||
logic [7:0] p; // p = l * 2 - q
|
||||
logic [7:0] qp; // qp = q - p
|
||||
|
||||
always_ff @ (posedge clock) begin
|
||||
tr <= h2 < 8'(`C2_3) ? h2 + 8'(`C1_3) : 8'(`C1_3) - minus1h;
|
||||
tg <= h2;
|
||||
tb <= h2 >= 8'(`C1_3) ? h2 - 8'(`C1_3) : minus1h;
|
||||
|
||||
p_pre <= (9'(l2) << 1) - q;
|
||||
qp <= 8'((q - l2) << 1);
|
||||
end
|
||||
|
||||
assign p = p_pre[8] ? 8'hff : p_pre[7:0];
|
||||
|
||||
/* propagate to next stage */
|
||||
logic [7:0] q3;
|
||||
always_ff @ (posedge clock)
|
||||
q3 <= q;
|
||||
|
||||
/* ---------------- stage 4 ---------------- */
|
||||
logic [7:0] trx, tgx, tbx;
|
||||
logic [10:0] qp6;
|
||||
|
||||
/* verilator lint_off UNUSED */
|
||||
logic [31:0] mac_r_o;
|
||||
logic [31:0] mac_g_o;
|
||||
logic [31:0] mac_b_o;
|
||||
/* verilator lint_on UNUSED */
|
||||
|
||||
assign qp6 = (11'(qp) << 1) + (11'(qp) << 2);
|
||||
assign trx = (tr < `C1_6) ? tr : `C2_3 - tr;
|
||||
assign tgx = (tg < `C1_6) ? tg : `C2_3 - tg;
|
||||
assign tbx = (tb < `C1_6) ? tb : `C2_3 - tb;
|
||||
|
||||
ice40_mac16x16 mac_r
|
||||
(.clock, .reset,
|
||||
.a({5'b0, qp6}),
|
||||
.b({8'b0, trx}),
|
||||
.s({16'b0, p, 8'b0}),
|
||||
.sub(1'b0),
|
||||
.y(mac_r_o));
|
||||
|
||||
ice40_mac16x16 mac_g
|
||||
(.clock, .reset,
|
||||
.a({5'b0, qp6}),
|
||||
.b({8'b0, tgx}),
|
||||
.s({16'b0, p, 8'b0}),
|
||||
.sub(1'b0),
|
||||
.y(mac_g_o));
|
||||
|
||||
ice40_mac16x16 mac_b
|
||||
(.clock, .reset,
|
||||
.a({5'b0, qp6}),
|
||||
.b({8'b0, tbx}),
|
||||
.s({16'b0, p, 8'b0}),
|
||||
.sub(1'b0),
|
||||
.y(mac_b_o));
|
||||
|
||||
/* propagate to next stage */
|
||||
logic [7:0] tr4, tg4, tb4;
|
||||
logic [7:0] p4;
|
||||
logic [7:0] q4;
|
||||
|
||||
always_ff @ (posedge clock) begin
|
||||
tr4 <= tr;
|
||||
tg4 <= tg;
|
||||
tb4 <= tb;
|
||||
p4 <= p;
|
||||
q4 <= q3;
|
||||
end
|
||||
|
||||
/* ---------------- stage 5 ---------------- */
|
||||
always_ff @ (posedge clock) begin
|
||||
if (tr4 < `C1_6) r <= mac_r_o[16] ? 8'hff : mac_r_o[15:8];
|
||||
else if (tr4 < `C1_2) r <= q4;
|
||||
else if (tr4 < `C2_3) r <= mac_r_o[16] ? 8'hff : mac_r_o[15:8];
|
||||
else r <= p4;
|
||||
end
|
||||
|
||||
always_ff @ (posedge clock) begin
|
||||
if (tg4 < `C1_6) g <= mac_g_o[16] ? 8'hff : mac_g_o[15:8];
|
||||
else if (tg4 < `C1_2) g <= q4;
|
||||
else if (tg4 < `C2_3) g <= mac_g_o[16] ? 8'hff : mac_g_o[15:8];
|
||||
else g <= p4;
|
||||
end
|
||||
|
||||
always_ff @ (posedge clock) begin
|
||||
if (tb4 < `C1_6) b <= mac_b_o[16] ? 8'hff : mac_b_o[15:8];
|
||||
else if (tb4 < `C1_2) b <= q4;
|
||||
else if (tb4 < `C2_3) b <= mac_b_o[16] ? 8'hff : mac_b_o[15:8];
|
||||
else b <= p4;
|
||||
end
|
||||
|
||||
endmodule // hsl2rgb
|
||||
98
source/hsv2rgb.sv
Normal file
98
source/hsv2rgb.sv
Normal file
@ -0,0 +1,98 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
|
||||
module hsv2rgb
|
||||
(input wire clock,
|
||||
input wire reset,
|
||||
|
||||
input wire [7:0] h,
|
||||
input wire [7:0] s,
|
||||
input wire [7:0] v,
|
||||
input wire ready_i,
|
||||
|
||||
output reg [7:0] r,
|
||||
output reg [7:0] g,
|
||||
output reg [7:0] b,
|
||||
output wire valid_o);
|
||||
|
||||
localparam STAGES = 2;
|
||||
logic [STAGES-1:0] valid;
|
||||
|
||||
assign valid_o = valid[STAGES-1];
|
||||
always_ff @ (posedge clock, posedge reset)
|
||||
if (reset) valid <= '0;
|
||||
else valid <= { valid[STAGES-2:0], ready_i };
|
||||
|
||||
/* ---------------- Stage 1 ---------------- */
|
||||
logic [7:0] flip_s;
|
||||
logic [7:0] vmin;
|
||||
logic [31:0] mac_vmin_o;
|
||||
logic [5:0] h_mod_43;
|
||||
|
||||
assign flip_s = 8'd255 - s;
|
||||
assign vmin = mac_vmin_o[15:8];
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
h_mod_43
|
||||
<= (h < 43) ? 6'(h) :
|
||||
(h < 86) ? 6'(h - 8'd43) :
|
||||
(h < 128) ? 6'(h - 8'd86) :
|
||||
(h < 171) ? 6'(h - 8'd128) :
|
||||
(h < 214) ? 6'(h - 8'd171) :
|
||||
6'(h - 8'd214);
|
||||
|
||||
ice40_mac16x16 mac_lls
|
||||
(.clock, .reset,
|
||||
.a({8'b0, flip_s}),
|
||||
.b({8'b0, v}),
|
||||
.s(32'b0),
|
||||
.sub(1'b0),
|
||||
.y(mac_vmin_o));
|
||||
|
||||
logic [7:0] h1, v1;
|
||||
always_ff @ (posedge clock) begin
|
||||
h1 <= h;
|
||||
v1 <= v;
|
||||
end
|
||||
|
||||
/* ---------------- Stage 2 ---------------- */
|
||||
logic [31:0] mac_a_o;
|
||||
logic [7:0] h_mod_43_6;
|
||||
logic [7:0] v_vmin;
|
||||
logic [7:0] a;
|
||||
|
||||
assign a = mac_a_o[15:8];
|
||||
|
||||
assign h_mod_43_6 = (8'(h_mod_43) << 1) + (8'(h_mod_43) << 2);
|
||||
assign v_vmin = v1 - vmin;
|
||||
|
||||
ice40_mac16x16 mac_a
|
||||
(.clock, .reset,
|
||||
.a({8'b0, v_vmin}),
|
||||
.b({8'b0, h_mod_43_6}),
|
||||
.s(32'b0),
|
||||
.sub(1'b0),
|
||||
.y(mac_a_o));
|
||||
|
||||
logic [7:0] h2, v2, vmin2;
|
||||
always_ff @ (posedge clock) begin
|
||||
h2 <= h1;
|
||||
v2 <= v1;
|
||||
vmin2 <= vmin;
|
||||
end
|
||||
|
||||
/* ---------------- Output ---------------- */
|
||||
logic [7:0] vinc, vdec;
|
||||
|
||||
assign vinc = vmin2 + a;
|
||||
assign vdec = v2 - a;
|
||||
|
||||
always_comb
|
||||
if (h2 < 43) {r, g, b} = {v2, vinc, vmin2};
|
||||
else if (h2 < 86) {r, g, b} = {vdec, v2, vmin2};
|
||||
else if (h2 < 128) {r, g, b} = {vmin2, v2, vinc};
|
||||
else if (h2 < 171) {r, g, b} = {vmin2, vdec, v2};
|
||||
else if (h2 < 214) {r, g, b} = {vinc, vmin2, v2};
|
||||
else {r, g, b} = {v2, vmin2, vdec};
|
||||
|
||||
endmodule // hsv2rgb
|
||||
135
source/hsx2rgb.rkt
Normal file
135
source/hsx2rgb.rkt
Normal file
@ -0,0 +1,135 @@
|
||||
#lang racket
|
||||
|
||||
(define (hsl2rgb h s l)
|
||||
(define (color q p h)
|
||||
(let ((tc (cond
|
||||
((> h 1) (- h 1))
|
||||
((< h 0) (+ h 1))
|
||||
(else h))))
|
||||
(cond
|
||||
((< tc 1/6) (+ p (* (- q p) tc 6)))
|
||||
((< tc 1/2) q)
|
||||
((< tc 2/3) (+ p (* (- q p) (- 2/3 tc) 6)))
|
||||
(else p))))
|
||||
(let* ((q (if (< l 0.5)
|
||||
(* l (+ 1 s))
|
||||
(+ l s (- (* l s)))))
|
||||
(p (- (* 2 l) q)))
|
||||
(values
|
||||
(inexact->exact (round (* 256 (color q p (+ h 1/3)))))
|
||||
(inexact->exact (round (* 256 (color q p h))))
|
||||
(inexact->exact (round (* 256 (color q p (- h 1/3))))))))
|
||||
|
||||
(define (hsl2rgb-ref h s l)
|
||||
(hsl2rgb (/ h 256) (/ s 256) (/ l 256)))
|
||||
|
||||
(define (hsv2rgb h s v)
|
||||
(let* ((hi (modulo (floor (/ h 256/6)) 6))
|
||||
(vmin (/ (* v (- 256 s)) 256))
|
||||
(a (* (- v vmin) (/ (modulo h 43) 256/6)))
|
||||
(vinc (+ vmin a))
|
||||
(vdec (- v a))
|
||||
|
||||
(vmin (inexact->exact (round vmin)))
|
||||
(vinc (inexact->exact (round vinc)))
|
||||
(vdec (inexact->exact (round vdec))))
|
||||
(cond
|
||||
((= hi 0) (values v vinc vmin))
|
||||
((= hi 1) (values vdec v vmin))
|
||||
((= hi 2) (values vmin v vinc))
|
||||
((= hi 3) (values vmin vdec v))
|
||||
((= hi 4) (values vinc vmin v))
|
||||
((= hi 5) (values v vmin vdec)))))
|
||||
|
||||
(define (hsv2rgb-int h s v)
|
||||
(define (byte-div-43-mod-6 x)
|
||||
(cond
|
||||
((< x 43) 0)
|
||||
((< x 86) 1)
|
||||
((< x 128) 2)
|
||||
((< x 171) 3)
|
||||
((< x 214) 4)
|
||||
(else 5)))
|
||||
|
||||
(define (byte-mod-43 x)
|
||||
(cond
|
||||
((< x 43) x)
|
||||
((< x 86) (- x 43))
|
||||
((< x 128) (- x 86))
|
||||
((< x 171) (- x 128))
|
||||
((< x 214) (- x 171))
|
||||
(else (- x 214))))
|
||||
|
||||
(define (*6 a) (+ (arithmetic-shift a 1)
|
||||
(arithmetic-shift a 2)))
|
||||
|
||||
(let* ((hi (byte-div-43-mod-6 h))
|
||||
(vmin (arithmetic-shift
|
||||
(* (- 255 s) v) -8))
|
||||
(a (arithmetic-shift
|
||||
(* (- v vmin)
|
||||
(*6 (byte-mod-43 h))) -8))
|
||||
(vinc (+ vmin a))
|
||||
(vdec (- v a)))
|
||||
(printf "hi=~a, vmin=~a, a=~a, vinc=~a, vdec=~a\n" hi vmin a vinc vdec)
|
||||
(cond
|
||||
((= hi 0) (values v vinc vmin))
|
||||
((= hi 1) (values vdec v vmin))
|
||||
((= hi 2) (values vmin v vinc))
|
||||
((= hi 3) (values vmin vdec v))
|
||||
((= hi 4) (values vinc vmin v))
|
||||
((= hi 5) (values v vmin vdec)))))
|
||||
|
||||
(define (hsl2rgb-int h s l)
|
||||
(define (*fp8 a b) (arithmetic-shift (* a b) -8))
|
||||
(define (*2 a) (arithmetic-shift a 1))
|
||||
(define (*6 a) (+ (arithmetic-shift a 1)
|
||||
(arithmetic-shift a 2)))
|
||||
|
||||
(define c1/6 43)
|
||||
(define c1/3 85)
|
||||
(define c1/2 128)
|
||||
(define c2/3 171)
|
||||
(define c1 256)
|
||||
|
||||
(let* ((l*s (*fp8 l s))
|
||||
(q (if (< l c1/2)
|
||||
(+ l l*s)
|
||||
(+ l s (- l*s))))
|
||||
(p (- (*2 l) q))
|
||||
(q-p ;;(- q p)
|
||||
(*2 (- q l)))
|
||||
(tr (if (< h c2/3) [+ h c1/3] [- c1/3 (- c1 h)]))
|
||||
(tg h)
|
||||
(tb (if (>= h c1/3) [- h c1/3] [- c1 h]))
|
||||
(q-p*6 (*6 q-p))
|
||||
|
||||
(r (cond
|
||||
((< tr c1/6) [+ p (*fp8 q-p*6 tr)])
|
||||
((< tr c1/2) q)
|
||||
((< tr c2/3) [+ p (*fp8 q-p*6 (- c2/3 tr))])
|
||||
(else p)))
|
||||
|
||||
(g (cond
|
||||
((< tg c1/6) [+ p (*fp8 q-p*6 tg)])
|
||||
((< tg c1/2) q)
|
||||
((< tg c2/3) [+ p (*fp8 q-p*6 (- c2/3 tg))])
|
||||
(else p)))
|
||||
|
||||
(b (cond
|
||||
((< tb c1/6) [+ p (*fp8 q-p*6 tb)])
|
||||
((< tb c1/2) q)
|
||||
((< tb c2/3) [+ p (*fp8 q-p*6 (- c2/3 tb))])
|
||||
(else p))))
|
||||
;; (printf "q=~a p=~a q-p=~a tr=~a tg=~a tb=~a\n" q p q-p tr tg tb)
|
||||
(values r g b)))
|
||||
|
||||
(define (p f h s x)
|
||||
(let-values (((r g b) (f h s x)))
|
||||
(printf "HSX ~a ~a ~a -> " h s x)
|
||||
(printf "RGB ~a ~a ~a\n\n" r g b)))
|
||||
|
||||
;;(p 20 255 100)
|
||||
(p hsv2rgb-int 50 100 150)
|
||||
(p hsv2rgb-int 111 222 33)
|
||||
(p hsv2rgb-int 200 150 50)
|
||||
81
source/ice40_2mac8x8.sv
Normal file
81
source/ice40_2mac8x8.sv
Normal file
@ -0,0 +1,81 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
|
||||
/* verilator lint_off PINCONNECTEMPTY */
|
||||
|
||||
module ice40_2mac8x8 #(parameter SIGNED = 0)
|
||||
(input wire clock,
|
||||
input wire reset,
|
||||
input wire [7:0] a0,
|
||||
input wire [7:0] b0,
|
||||
input wire [15:0] s0,
|
||||
input wire sub0,
|
||||
output wire [15:0] y0,
|
||||
|
||||
input wire [7:0] a1,
|
||||
input wire [7:0] b1,
|
||||
input wire [15:0] s1,
|
||||
input wire sub1,
|
||||
output wire [15:0] y1);
|
||||
|
||||
/* register 'sub' input */
|
||||
logic sub0_r, sub1_r;
|
||||
always_ff @ (posedge clock) begin
|
||||
sub0_r <= sub0;
|
||||
sub1_r <= sub1;
|
||||
end
|
||||
|
||||
logic [31:0] mac_o;
|
||||
assign {y0, y1} = mac_o;
|
||||
|
||||
SB_MAC16
|
||||
#(.NEG_TRIGGER(1'b0),
|
||||
.C_REG(1'b1), // Registered C
|
||||
.A_REG(1'b1), // Registered A
|
||||
.B_REG(1'b1), // Registered B
|
||||
.D_REG(1'b1), // Registered D
|
||||
.TOP_8x8_MULT_REG(1'b0),
|
||||
.BOT_8x8_MULT_REG(1'b0),
|
||||
.PIPELINE_16x16_MULT_REG1(1'b0),
|
||||
.PIPELINE_16x16_MULT_REG2(1'b0),
|
||||
.TOPOUTPUT_SELECT(2'b00), // TOP output - ADD/SUB unregistered
|
||||
.TOPADDSUB_LOWERINPUT(2'b01), // TOP adder input 1 - 8x8 top multiplier output
|
||||
.TOPADDSUB_UPPERINPUT(1'b1), // TOP adder input 2 - input C
|
||||
.TOPADDSUB_CARRYSELECT(2'b00), // TOP adder carry input - constant 0
|
||||
.BOTOUTPUT_SELECT(2'b00), // BOT output - ADD/SUB unregistered
|
||||
.BOTADDSUB_LOWERINPUT(2'b01), // BOT adder input 1 - 8x8 bot multiplier output
|
||||
.BOTADDSUB_UPPERINPUT(1'b1), // BOT adder input 2 - input D
|
||||
.BOTADDSUB_CARRYSELECT(2'b00), // BOT adder carry input - constant 0
|
||||
.MODE_8x8(1'b1),
|
||||
.A_SIGNED(SIGNED),
|
||||
.B_SIGNED(SIGNED))
|
||||
mac_r
|
||||
(.CLK(clock),
|
||||
.CE(1'b1),
|
||||
.C(s0),
|
||||
.A({a0, a1}),
|
||||
.B({b0, b1}),
|
||||
.D(s1),
|
||||
.AHOLD(1'b0),
|
||||
.BHOLD(1'b0),
|
||||
.CHOLD(1'b0),
|
||||
.DHOLD(1'b0),
|
||||
.IRSTTOP(reset),
|
||||
.IRSTBOT(reset),
|
||||
.ORSTTOP(reset),
|
||||
.ORSTBOT(reset),
|
||||
.OLOADTOP(1'b0),
|
||||
.OLOADBOT(1'b0),
|
||||
.ADDSUBTOP(sub0_r),
|
||||
.ADDSUBBOT(sub1_r),
|
||||
.OHOLDTOP(1'b0),
|
||||
.OHOLDBOT(1'b0),
|
||||
.CI(1'b0),
|
||||
.ACCUMCI(1'b0),
|
||||
.SIGNEXTIN(1'b0),
|
||||
.O(mac_o),
|
||||
.CO(),
|
||||
.ACCUMCO(),
|
||||
.SIGNEXTOUT());
|
||||
|
||||
endmodule // ice40_macadd16x16
|
||||
70
source/ice40_mac16x16.sv
Normal file
70
source/ice40_mac16x16.sv
Normal file
@ -0,0 +1,70 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
|
||||
/* verilator lint_off PINCONNECTEMPTY */
|
||||
|
||||
module ice40_mac16x16 #(parameter SIGNED = 0)
|
||||
(input wire clock,
|
||||
input wire reset,
|
||||
input wire [15:0] a,
|
||||
input wire [15:0] b,
|
||||
input wire [31:0] s,
|
||||
input wire sub,
|
||||
output wire [31:0] y);
|
||||
|
||||
/* register 'sub' input */
|
||||
logic sub_r;
|
||||
always_ff @ (posedge clock)
|
||||
sub_r <= sub;
|
||||
|
||||
SB_MAC16
|
||||
#(.NEG_TRIGGER(1'b0),
|
||||
.C_REG(1'b1), // Registered C
|
||||
.A_REG(1'b1), // Registered A
|
||||
.B_REG(1'b1), // Registered B
|
||||
.D_REG(1'b1), // Registered D
|
||||
.TOP_8x8_MULT_REG(1'b0),
|
||||
.BOT_8x8_MULT_REG(1'b0),
|
||||
.PIPELINE_16x16_MULT_REG1(1'b0),
|
||||
.PIPELINE_16x16_MULT_REG2(1'b0),
|
||||
.TOPOUTPUT_SELECT(2'b00), // TOP output - ADD/SUB unregistered
|
||||
.TOPADDSUB_LOWERINPUT(2'b10), // TOP adder input 1 - 16x16 multiplier upper word
|
||||
.TOPADDSUB_UPPERINPUT(1'b1), // TOP adder input 2 - input C
|
||||
.TOPADDSUB_CARRYSELECT(2'b00), // TOP adder carry input - constant 0
|
||||
.BOTOUTPUT_SELECT(2'b00), // BOT output - ADD/SUB unregistered
|
||||
.BOTADDSUB_LOWERINPUT(2'b10), // BOT adder input 1 - 16x16 multiplier lower word
|
||||
.BOTADDSUB_UPPERINPUT(1'b1), // BOT adder input 2 - input D
|
||||
.BOTADDSUB_CARRYSELECT(2'b00), // BOT adder carry input - constant 0
|
||||
.MODE_8x8(1'b0),
|
||||
.A_SIGNED(SIGNED),
|
||||
.B_SIGNED(SIGNED))
|
||||
mac_r
|
||||
(.CLK(clock),
|
||||
.CE(1'b1),
|
||||
.C(s[31:16]),
|
||||
.A(a),
|
||||
.B(b),
|
||||
.D(s[15:0]),
|
||||
.AHOLD(1'b0),
|
||||
.BHOLD(1'b0),
|
||||
.CHOLD(1'b0),
|
||||
.DHOLD(1'b0),
|
||||
.IRSTTOP(reset),
|
||||
.IRSTBOT(reset),
|
||||
.ORSTTOP(reset),
|
||||
.ORSTBOT(reset),
|
||||
.OLOADTOP(1'b0),
|
||||
.OLOADBOT(1'b0),
|
||||
.ADDSUBTOP(sub_r),
|
||||
.ADDSUBBOT(sub_r),
|
||||
.OHOLDTOP(1'b0),
|
||||
.OHOLDBOT(1'b0),
|
||||
.CI(1'b0),
|
||||
.ACCUMCI(1'b0),
|
||||
.SIGNEXTIN(1'b0),
|
||||
.O(y),
|
||||
.CO(),
|
||||
.ACCUMCO(),
|
||||
.SIGNEXTOUT());
|
||||
|
||||
endmodule // ice40_macadd16x16
|
||||
94
source/ice40_spram.sv
Normal file
94
source/ice40_spram.sv
Normal file
@ -0,0 +1,94 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
|
||||
module ice40_spram
|
||||
(input wire clock,
|
||||
input wire [15:0] addr,
|
||||
input wire [15:0] data_i,
|
||||
output wire [15:0] data_o,
|
||||
input wire wr);
|
||||
|
||||
logic [15:0] data0_o;
|
||||
logic [15:0] data1_o;
|
||||
logic [15:0] data2_o;
|
||||
logic [15:0] data3_o;
|
||||
logic w0, w1, w2, w3;
|
||||
|
||||
logic [15:0] datax_o;
|
||||
assign data_o = datax_o;
|
||||
|
||||
always @(*) begin
|
||||
{w0, w1, w2, w3} = '0;
|
||||
|
||||
case (addr[15:14])
|
||||
2'd0: begin
|
||||
datax_o = data0_o;
|
||||
w0 = wr;
|
||||
end
|
||||
|
||||
2'd1: begin
|
||||
datax_o = data1_o;
|
||||
w1 = wr;
|
||||
end
|
||||
|
||||
2'd2: begin
|
||||
datax_o = data2_o;
|
||||
w2 = wr;
|
||||
end
|
||||
|
||||
2'd3: begin
|
||||
datax_o = data3_o;
|
||||
w3 = wr;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
SB_SPRAM256KA spram0
|
||||
(.CLOCK(clock),
|
||||
.ADDRESS(addr[13:0]),
|
||||
.DATAIN(data_i),
|
||||
.DATAOUT(data0_o),
|
||||
.WREN(w0),
|
||||
.MASKWREN({w0, w0, w0, w0}),
|
||||
.CHIPSELECT(1'b1),
|
||||
.STANDBY(1'b0),
|
||||
.SLEEP(1'b0),
|
||||
.POWEROFF(1'b1));
|
||||
|
||||
SB_SPRAM256KA spram1
|
||||
(.CLOCK(clock),
|
||||
.ADDRESS(addr[13:0]),
|
||||
.DATAIN(data_i),
|
||||
.DATAOUT(data1_o),
|
||||
.WREN(w1),
|
||||
.MASKWREN({w1, w1, w1, w1}),
|
||||
.CHIPSELECT(1'b1),
|
||||
.STANDBY(1'b0),
|
||||
.SLEEP(1'b0),
|
||||
.POWEROFF(1'b1));
|
||||
|
||||
SB_SPRAM256KA spram2
|
||||
(.CLOCK(clock),
|
||||
.ADDRESS(addr[13:0]),
|
||||
.DATAIN(data_i),
|
||||
.DATAOUT(data2_o),
|
||||
.WREN(w2),
|
||||
.MASKWREN({w2, w2, w2, w2}),
|
||||
.CHIPSELECT(1'b1),
|
||||
.STANDBY(1'b0),
|
||||
.SLEEP(1'b0),
|
||||
.POWEROFF(1'b1));
|
||||
|
||||
SB_SPRAM256KA spram3
|
||||
(.CLOCK(clock),
|
||||
.ADDRESS(addr[13:0]),
|
||||
.DATAIN(data_i),
|
||||
.DATAOUT(data3_o),
|
||||
.WREN(w3),
|
||||
.MASKWREN({w3, w3, w3, w3}),
|
||||
.CHIPSELECT(1'b1),
|
||||
.STANDBY(1'b0),
|
||||
.SLEEP(1'b0),
|
||||
.POWEROFF(1'b1));
|
||||
|
||||
endmodule // ice40_spram
|
||||
80
source/lcd_init.rom
Normal file
80
source/lcd_init.rom
Normal file
@ -0,0 +1,80 @@
|
||||
0CF // ---- Power control B
|
||||
100 // default
|
||||
1C9 // (or C1) непонятно что это. По документу вообще нужно 89 или 81
|
||||
130 // default
|
||||
|
||||
0ED // ---- Power on sequence
|
||||
164 // ?
|
||||
103 // ?
|
||||
112 // ?
|
||||
181 // DDVDH enhance mode
|
||||
|
||||
0E8 // ---- Driver timing control A
|
||||
185 // Gate driver overlap timing +1unit (?)
|
||||
110 // ?
|
||||
17A // Precharge (default)
|
||||
|
||||
0CB // ---- Power control A
|
||||
139 // default
|
||||
12C // default
|
||||
100 // default
|
||||
134 // default (Vcore = 1.6V)
|
||||
102 // default (DDVDH = 5.6V)
|
||||
|
||||
0F7 // ---- Pump ratio control
|
||||
120 // DDVDH = 2xVCI
|
||||
|
||||
0EA // ---- Driver timing control B
|
||||
100 // ?
|
||||
100 // default
|
||||
|
||||
0C0 // ---- Power control 1
|
||||
11B // VRH = 4.2V
|
||||
|
||||
0C1 // ---- Power control 2
|
||||
100 // ?
|
||||
|
||||
0C5 // ---- VCOM control 1
|
||||
130 // (or 3F) VCOMH = 3.9V
|
||||
130 // (or 3C) VCOML = -1.3V
|
||||
|
||||
0C7 // ---- VCOM control 2
|
||||
1B7 // VCOMH = VMH-9, VCOML = VML-9
|
||||
|
||||
036 // ---- Memory Access Control
|
||||
108 // RGB reverse
|
||||
|
||||
03A // ---- Pixel format set
|
||||
155 // 66 - 18 bit per pixel, 55 - 16 bit per pixel
|
||||
|
||||
0F6 // ---- Interface control
|
||||
101 // default
|
||||
110 // EPF=01 (RGB mapping to 16-bit word)
|
||||
|
||||
0B1 // ---- Frame rate control
|
||||
100 // fosc/1
|
||||
11A // 26 clock per line (default - 1B)
|
||||
|
||||
0B6 // ---- Display Function Control (отсутствуют два параметра)
|
||||
10A // default
|
||||
1A2 // Reverse shift direction
|
||||
|
||||
0F2 // ---- 3Gamma Function Disable
|
||||
100
|
||||
|
||||
026 // ---- Gamma curve
|
||||
101 // default
|
||||
|
||||
02B // ---- Page address set 0..319
|
||||
100
|
||||
100
|
||||
101
|
||||
13f
|
||||
|
||||
02A // ---- Column address set 0..239
|
||||
100
|
||||
100
|
||||
100
|
||||
1ef
|
||||
|
||||
011 // ---- Exit Sleep
|
||||
98
source/lcd_spi.sv
Normal file
98
source/lcd_spi.sv
Normal file
@ -0,0 +1,98 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
|
||||
`include "assert.vh"
|
||||
|
||||
module lcd_spi #(parameter DATA_WIDTH = 8,
|
||||
parameter SPI_CLK_PERIOD = 10,
|
||||
parameter PUSH_ON_DONE = 0)
|
||||
(input wire clock,
|
||||
input wire reset,
|
||||
|
||||
input wire [DATA_WIDTH-1:0] data_i,
|
||||
input wire push_i,
|
||||
output reg done_o,
|
||||
|
||||
output reg spi_clk_o,
|
||||
output wire spi_dat_o);
|
||||
|
||||
initial begin
|
||||
`assert(DATA_WIDTH > 0);
|
||||
`assert(SPI_CLK_PERIOD >= 2);
|
||||
end
|
||||
|
||||
localparam SCLK_LOW = SPI_CLK_PERIOD / 2;
|
||||
|
||||
logic [$clog2(SPI_CLK_PERIOD)-1:0] sclk_cntr;
|
||||
logic sclk_one;
|
||||
logic sclk_nededge;
|
||||
logic do_push;
|
||||
|
||||
assign sclk_one = (sclk_cntr < SCLK_LOW) ? 1'b0 : 1'b1;
|
||||
|
||||
always_ff @ (posedge clock, posedge reset)
|
||||
if (reset) begin
|
||||
sclk_cntr <= '0;
|
||||
sclk_nededge <= 1'b0;
|
||||
spi_clk_o <= 1'b0;
|
||||
end
|
||||
else begin
|
||||
sclk_nededge <= 1'b0;
|
||||
spi_clk_o <= do_push ? sclk_one : 1'b0;
|
||||
|
||||
if (do_push || sclk_one) begin
|
||||
if (sclk_cntr == (SPI_CLK_PERIOD-1)) begin
|
||||
sclk_cntr <= '0;
|
||||
sclk_nededge <= 1'b1;
|
||||
end
|
||||
else
|
||||
sclk_cntr <= sclk_cntr + 1'b1;
|
||||
end
|
||||
else
|
||||
sclk_cntr <= '0;
|
||||
end
|
||||
|
||||
localparam BIT_CW = $clog2(DATA_WIDTH);
|
||||
logic [BIT_CW-1:0] sbit_cntr;
|
||||
logic [DATA_WIDTH-1:0] data_sr;
|
||||
|
||||
assign spi_dat_o = data_sr[DATA_WIDTH-1];
|
||||
|
||||
logic push;
|
||||
|
||||
generate
|
||||
if (PUSH_ON_DONE == 0)
|
||||
assign push = push_i & done_o;
|
||||
else
|
||||
assign push = push_i;
|
||||
endgenerate
|
||||
|
||||
always_ff @(posedge clock, posedge reset)
|
||||
if (reset) begin
|
||||
do_push <= 1'b0;
|
||||
done_o <= 1'b0;
|
||||
end
|
||||
else begin
|
||||
if (do_push) begin
|
||||
if (sclk_nededge) begin
|
||||
data_sr <= data_sr << 1;
|
||||
sbit_cntr <= sbit_cntr + 1'b1;
|
||||
|
||||
if (sbit_cntr == BIT_CW'(DATA_WIDTH-1)) begin
|
||||
do_push <= 1'b0;
|
||||
done_o <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
else begin
|
||||
done_o <= 1'b0;
|
||||
|
||||
if (push) begin
|
||||
data_sr <= data_i;
|
||||
sbit_cntr <= '0;
|
||||
do_push <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule // lcd_spi
|
||||
737
source/lcd_top.sv
Normal file
737
source/lcd_top.sv
Normal file
@ -0,0 +1,737 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
|
||||
/* Yosys do not support SPRAM and MAC inferring */
|
||||
`define USE_SPRAM_PRIMITIVE
|
||||
`define USE_MAC_PRIMITIVE
|
||||
|
||||
module lcd_top #(parameter SPI_CLK_PERIOD = 6)
|
||||
(input logic clock,
|
||||
input logic reset,
|
||||
|
||||
output logic lcd_spi_csn_o,
|
||||
output logic lcd_spi_clk_o,
|
||||
output logic lcd_spi_dat_o,
|
||||
output logic lcd_spi_dcn_o,
|
||||
|
||||
input logic redraw_i,
|
||||
output logic done_o,
|
||||
|
||||
input logic [7:0] x_i,
|
||||
input logic [8:0] y_i,
|
||||
input logic [15:0] color_i,
|
||||
output logic [15:0] color_o,
|
||||
input logic req_i,
|
||||
output logic ack_o,
|
||||
input logic wr_i);
|
||||
|
||||
/* Display size */
|
||||
localparam DISPLAY_MEM_SIZE = 320 * 240 * 2; // 2 byte per pixel
|
||||
localparam DISPLAY_MEM_CW = $clog2(DISPLAY_MEM_SIZE);
|
||||
|
||||
/* Display x/y address width */
|
||||
localparam DISPLAY_XCW = 8,
|
||||
DISPLAY_YCW = 9;
|
||||
|
||||
/* Screen size and origin */
|
||||
localparam XSIZE = 240,
|
||||
YSIZE = 272,
|
||||
XORIG = 0,
|
||||
YORIG = 24;
|
||||
|
||||
localparam FBSIZE = XSIZE * YSIZE;
|
||||
localparam FBCW = $clog2(FBSIZE);
|
||||
|
||||
/* Drawing block size */
|
||||
localparam BLOCK_XS = 16, // must be power of 2
|
||||
BLOCK_YS = 16; // must be power of 2
|
||||
|
||||
localparam GRID_XS = XSIZE / BLOCK_XS,
|
||||
GRID_YS = YSIZE / BLOCK_YS;
|
||||
|
||||
localparam BLOCK_XS_CW = $clog2(BLOCK_XS);
|
||||
localparam BLOCK_YS_CW = $clog2(BLOCK_YS);
|
||||
|
||||
localparam GRID_XS_CW = $clog2(GRID_XS);
|
||||
localparam GRID_YS_CW = $clog2(GRID_YS);
|
||||
|
||||
localparam DFLAG_SIZE = GRID_XS * GRID_YS;
|
||||
localparam DFLAG_CW = $clog2(DFLAG_SIZE);
|
||||
|
||||
localparam BLOCK_SIZE = BLOCK_XS * BLOCK_YS;
|
||||
localparam BLOCK_CW = $clog2(BLOCK_SIZE);
|
||||
|
||||
/* --------- Drawing flags memory --------- */
|
||||
logic dflag[DFLAG_SIZE];
|
||||
logic dflag_wdata;
|
||||
logic dflag_rdata;
|
||||
logic [DFLAG_CW-1:0] dflag_waddr;
|
||||
logic [DFLAG_CW-1:0] dflag_raddr;
|
||||
logic [DFLAG_CW-1:0] dflag_int_addr; // for screen refresher
|
||||
logic [DFLAG_CW-1:0] dflag_ext_addr; // for external master
|
||||
logic dflag_wr;
|
||||
logic dflag_set;
|
||||
logic dflag_clr;
|
||||
|
||||
assign dflag_wr = dflag_set | dflag_clr;
|
||||
assign dflag_waddr = dflag_clr ? dflag_int_addr : dflag_ext_addr;
|
||||
assign dflag_raddr = dflag_int_addr;
|
||||
assign dflag_wdata = dflag_set;
|
||||
|
||||
/* Infer as sysMEM Block RAM */
|
||||
always_ff @ (posedge clock) begin
|
||||
if (dflag_wr)
|
||||
dflag[dflag_waddr] <= dflag_wdata;
|
||||
|
||||
dflag_rdata <= dflag[dflag_raddr];
|
||||
end
|
||||
|
||||
/* --------- Frame buffer RAM (one-port block RAM)--------- */
|
||||
logic [FBCW-1:0] fbaddr;
|
||||
logic [15:0] fb_rdata;
|
||||
logic [15:0] fb_wdata;
|
||||
logic fbwrite;
|
||||
|
||||
`ifdef USE_SPRAM_PRIMITIVE
|
||||
ice40_spram spram_i
|
||||
(.clock(clock),
|
||||
.addr(fbaddr),
|
||||
.data_i(fb_wdata),
|
||||
.data_o(fb_rdata),
|
||||
.wr(fbwrite));
|
||||
`else
|
||||
logic [15:0] fbram[FBSIZE];
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
if (fbwrite) begin
|
||||
fbram[fbaddr] <= fb_wdata;
|
||||
fb_rdata <= 'x;
|
||||
end
|
||||
else
|
||||
fb_rdata <= fbram[fbaddr];
|
||||
`endif
|
||||
|
||||
/* --------- Framebuffer arbiter --------- */
|
||||
logic [FBCW-1:0] fba_int; // Frame buffer address from refresher
|
||||
logic [FBCW-1:0] fba_ext; // Frame buffer address from client
|
||||
|
||||
logic fb_busy_int;
|
||||
logic fb_busy_ext;
|
||||
logic fb_clear;
|
||||
|
||||
assign fbaddr = fb_busy_int ? fba_int : fba_ext;
|
||||
assign color_o = fb_rdata;
|
||||
assign fb_wdata = fb_clear ? '0 : color_i;
|
||||
|
||||
enum int unsigned {
|
||||
FBST_CLEAR = 0,
|
||||
FBST_CLEAR_NEXT,
|
||||
FBST_WAIT,
|
||||
FBST_ADDR,
|
||||
FBST_READ,
|
||||
FBST_DONE
|
||||
} fbst;
|
||||
|
||||
logic [FBCW-1:0] ymult;
|
||||
logic [DFLAG_CW-1:0] fmult;
|
||||
|
||||
`ifdef USE_MAC_PRIMITIVE
|
||||
wire [31:0] ymac_o;
|
||||
wire [31:0] fmac_o;
|
||||
|
||||
ice40_mac16x16 ymac_i
|
||||
(.clock, .reset,
|
||||
.a(16'(y_i)),
|
||||
.b(16'(XSIZE)),
|
||||
.s(32'b0),
|
||||
.sub(1'b0),
|
||||
.y(ymac_o));
|
||||
|
||||
ice40_mac16x16 fmac_i
|
||||
(.clock, .reset,
|
||||
.a(16'(y_i) >> BLOCK_YS_CW),
|
||||
.b(16'(GRID_XS)),
|
||||
.s(32'b0),
|
||||
.sub(1'b0),
|
||||
.y(fmac_o));
|
||||
|
||||
assign ymult = ymac_o[FBCW-1:0];
|
||||
assign fmult = fmac_o[DFLAG_CW-1:0];
|
||||
`endif
|
||||
|
||||
always_ff @ (posedge clock, posedge reset)
|
||||
if (reset) begin
|
||||
fbst <= FBST_CLEAR;
|
||||
ack_o <= 1'b0;
|
||||
fbwrite <= 1'b0;
|
||||
fb_busy_ext <= 1'b0;
|
||||
dflag_set <= 1'b0;
|
||||
end
|
||||
else
|
||||
case (fbst)
|
||||
/* Clear frame buffer RAM */
|
||||
FBST_CLEAR: begin
|
||||
fba_ext <= '0;
|
||||
fbwrite <= 1'b1;
|
||||
fb_busy_ext <= 1'b1;
|
||||
fb_clear <= 1'b1;
|
||||
fbst <= FBST_CLEAR_NEXT;
|
||||
end
|
||||
|
||||
FBST_CLEAR_NEXT:
|
||||
if (fba_ext == (FBSIZE-1)) begin
|
||||
fbwrite <= 1'b0;
|
||||
fb_busy_ext <= 1'b0;
|
||||
fb_clear <= 1'b0;
|
||||
fbst <= FBST_WAIT;
|
||||
end
|
||||
else
|
||||
fba_ext <= fba_ext + 1'b1;
|
||||
|
||||
/* Main loop */
|
||||
FBST_WAIT:
|
||||
if (req_i && !fb_busy_int)
|
||||
if (x_i >= XSIZE || y_i >= YSIZE) begin
|
||||
ack_o <= 1'b1;
|
||||
fbst <= FBST_READ;
|
||||
end
|
||||
else begin
|
||||
|
||||
`ifndef USE_MAC_PRIMITIVE
|
||||
ymult <= y_i * XSIZE;
|
||||
fmult <= GRID_YS_CW'(y_i >> BLOCK_YS_CW) * GRID_XS;
|
||||
`endif
|
||||
fb_busy_ext <= 1'b1;
|
||||
fbst <= FBST_ADDR;
|
||||
end
|
||||
|
||||
FBST_ADDR:
|
||||
if (fb_busy_int) begin
|
||||
fbst <= FBST_WAIT;
|
||||
fb_busy_ext <= 1'b0;
|
||||
end
|
||||
else begin
|
||||
fba_ext <= ymult + FBCW'(x_i);
|
||||
dflag_ext_addr <= fmult + DFLAG_CW'(x_i >> BLOCK_XS_CW);
|
||||
|
||||
if (wr_i) begin
|
||||
ack_o <= 1'b1;
|
||||
fbwrite <= 1'b1;
|
||||
dflag_set <= 1'b1;
|
||||
fbst <= FBST_DONE;
|
||||
end
|
||||
else
|
||||
fbst <= FBST_READ;
|
||||
end
|
||||
|
||||
FBST_READ: begin
|
||||
ack_o <= 1'b1;
|
||||
fbst <= FBST_DONE;
|
||||
end
|
||||
|
||||
FBST_DONE: begin
|
||||
fbwrite <= 1'b0;
|
||||
dflag_set <= 1'b0;
|
||||
ack_o <= 1'b0;
|
||||
fb_busy_ext <= 1'b0;
|
||||
fbst <= FBST_WAIT;
|
||||
end
|
||||
endcase
|
||||
|
||||
/* --------- Read initialization commands from file --------- */
|
||||
localparam INIT_FILE = "lcd_init.rom";
|
||||
localparam INIT_ROM_SIZE = 64;
|
||||
localparam INIT_DATA_SIZE = 61;
|
||||
localparam INIT_ROM_CW = $clog2(INIT_ROM_SIZE);
|
||||
|
||||
logic [8:0] init_rom [INIT_ROM_SIZE];
|
||||
logic [INIT_ROM_CW-1:0] init_addr;
|
||||
logic [8:0] init_data;
|
||||
|
||||
initial $readmemh(INIT_FILE, init_rom, 0, INIT_DATA_SIZE-1);
|
||||
|
||||
/* Block RAM as ROM */
|
||||
always_ff @ (posedge clock)
|
||||
init_data <= init_rom[init_addr];
|
||||
|
||||
/* --------- SPI master --------- */
|
||||
logic [7:0] spi_data;
|
||||
logic spi_push;
|
||||
logic spi_done;
|
||||
|
||||
lcd_spi #(.DATA_WIDTH(8),
|
||||
.SPI_CLK_PERIOD(SPI_CLK_PERIOD),
|
||||
.PUSH_ON_DONE(1)) spim_i
|
||||
(.clock, .reset,
|
||||
.data_i(spi_data),
|
||||
.push_i(spi_push),
|
||||
.done_o(spi_done),
|
||||
.spi_clk_o(lcd_spi_clk_o),
|
||||
.spi_dat_o(lcd_spi_dat_o));
|
||||
|
||||
/* --------- Main FSM --------- */
|
||||
`ifdef TESTBENCH
|
||||
localparam INIT_DELAY = 250;
|
||||
`else
|
||||
// localparam INIT_DELAY = 7500000;
|
||||
localparam INIT_DELAY = 250;
|
||||
`endif
|
||||
|
||||
enum int unsigned {
|
||||
ST_PREINIT_DELAY = 0, // 0
|
||||
ST_INIT_PUSH_SPI,
|
||||
ST_INIT_WAIT_SPI,
|
||||
ST_INIT_WAIT_LAST,
|
||||
ST_POSTINIT_DELAY,
|
||||
ST_DISPLAY_ON,
|
||||
ST_DISPLAY_ONW,
|
||||
ST_SCRCLR_CMD,
|
||||
ST_SCRCLR,
|
||||
ST_SCRCLR_LAST,
|
||||
ST_START_REDRAW, // 10
|
||||
ST_READ_FLAG,
|
||||
ST_CHECK_FLAG,
|
||||
ST_CLEAR_FLAG,
|
||||
ST_CADDR_CMD,
|
||||
ST_CADDR_0,
|
||||
ST_CADDR_1,
|
||||
ST_CADDR_2,
|
||||
ST_CADDR_3,
|
||||
ST_PADDR_CMD,
|
||||
ST_PADDR_0, // 20
|
||||
ST_PADDR_1,
|
||||
ST_PADDR_2,
|
||||
ST_PADDR_3,
|
||||
ST_WRITE_CMD,
|
||||
ST_WRITE_CMDW,
|
||||
ST_FB_READ,
|
||||
ST_STORE_PIXEL,
|
||||
ST_WRITE_PIXEL_H,
|
||||
ST_WRITE_PIXEL_L,
|
||||
ST_NEXT_PIXEL, // 30
|
||||
ST_NEXT_BLOCK
|
||||
} state, next;
|
||||
|
||||
always_ff @(posedge clock, posedge reset)
|
||||
if (reset) state <= ST_PREINIT_DELAY;
|
||||
else state <= next;
|
||||
|
||||
/* Pre/post init delay counter */
|
||||
localparam INIT_DELAY_CW = $clog2(INIT_DELAY);
|
||||
logic [INIT_DELAY_CW-1:0] delay_cntr;
|
||||
logic delay_cntr_incr;
|
||||
|
||||
always_ff @(posedge clock)
|
||||
delay_cntr <= (~reset && delay_cntr_incr) ?
|
||||
delay_cntr + 1'b1 : '0;
|
||||
|
||||
/* Initialization ROM address */
|
||||
logic init_addr_rst;
|
||||
logic init_addr_incr;
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
if (reset || init_addr_rst)
|
||||
init_addr <= '0;
|
||||
else
|
||||
if (init_addr_incr)
|
||||
init_addr <= init_addr + 1'b1;
|
||||
|
||||
/* LCD chipselect */
|
||||
logic spi_disable;
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
if (reset || spi_disable)
|
||||
lcd_spi_csn_o <= 1'b1;
|
||||
else if (spi_push)
|
||||
lcd_spi_csn_o <= 1'b0;
|
||||
|
||||
/* LCD data/command */
|
||||
logic spi_do_cmd;
|
||||
logic spi_do_data;
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
// if (spi_do_cmd)
|
||||
// lcd_spi_dcn_o <= 1'b0;
|
||||
// else if (spi_do_data)
|
||||
// lcd_spi_dcn_o <= 1'b1;
|
||||
if (spi_do_cmd != spi_do_data)
|
||||
lcd_spi_dcn_o <= spi_do_data;
|
||||
|
||||
/* Redraw block coordinates */
|
||||
logic [GRID_XS_CW-1:0] bx;
|
||||
logic [DISPLAY_XCW-1:0] borigx;
|
||||
logic [DISPLAY_YCW-1:0] borigy;
|
||||
logic [DISPLAY_XCW-1:0] borigx_e;
|
||||
logic [DISPLAY_YCW-1:0] borigy_e;
|
||||
|
||||
assign borigx_e = borigx + BLOCK_XS - 1;
|
||||
assign borigy_e = borigy + BLOCK_YS - 1;
|
||||
|
||||
logic [FBCW-1:0] fbr_orig;
|
||||
|
||||
logic reset_redraw;
|
||||
logic next_block;
|
||||
logic is_last_blk;
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
if (reset_redraw) begin
|
||||
dflag_int_addr <= '0;
|
||||
bx <= '0;
|
||||
borigx <= XORIG;
|
||||
borigy <= YORIG;
|
||||
fbr_orig <= '0;
|
||||
is_last_blk <= 1'b0;
|
||||
end
|
||||
else
|
||||
if (next_block) begin
|
||||
dflag_int_addr <= dflag_int_addr + 1'b1;
|
||||
is_last_blk <= (dflag_int_addr == DFLAG_CW'(DFLAG_SIZE-1)) ? 1'b1 : 1'b0;
|
||||
|
||||
if (bx == GRID_XS_CW'(GRID_XS - 1))
|
||||
begin
|
||||
bx <= '0;
|
||||
borigx <= XORIG;
|
||||
borigy <= borigy + BLOCK_YS;
|
||||
fbr_orig <= fbr_orig + BLOCK_XS + ((BLOCK_YS - 1) * XSIZE);
|
||||
end
|
||||
else
|
||||
begin
|
||||
bx <= bx + 1'b1;
|
||||
borigx <= borigx + BLOCK_XS;
|
||||
fbr_orig <= fbr_orig + BLOCK_XS;
|
||||
end
|
||||
end
|
||||
|
||||
/* Framebuffer handling */
|
||||
logic [BLOCK_XS_CW-1:0] px;
|
||||
logic [BLOCK_CW-1:0] pi;
|
||||
logic [15:0] pixel;
|
||||
|
||||
logic start_write;
|
||||
logic read_pixel;
|
||||
logic next_pixel;
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
if (read_pixel)
|
||||
pixel <= fb_rdata;
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
if (start_write) begin
|
||||
fba_int <= fbr_orig;
|
||||
px <= '0;
|
||||
pi <= '0;
|
||||
end
|
||||
else
|
||||
if (next_pixel) begin
|
||||
pi <= pi + 1'b1;
|
||||
|
||||
if (px == BLOCK_XS_CW'(BLOCK_XS-1))
|
||||
begin
|
||||
fba_int <= fba_int + XSIZE - BLOCK_XS + 1'b1;
|
||||
px <= '0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
fba_int <= fba_int + 1'b1;
|
||||
px <= px + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
/* Column/page addresses map */
|
||||
logic [15:0] caddr_b, caddr_e;
|
||||
logic [15:0] paddr_b, paddr_e;
|
||||
|
||||
assign caddr_b = { (16-DISPLAY_XCW)'('0), borigx };
|
||||
assign caddr_e = { (16-DISPLAY_XCW)'('0), borigx_e };
|
||||
assign paddr_b = { (16-DISPLAY_YCW)'('0), borigy };
|
||||
assign paddr_e = { (16-DISPLAY_YCW)'('0), borigy_e };
|
||||
|
||||
/* Clear screen pixel counter */
|
||||
logic [DISPLAY_MEM_CW-1:0] scrclr_pcntr;
|
||||
logic scrclr_incr;
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
if (reset || init_addr_rst)
|
||||
scrclr_pcntr <= '0;
|
||||
else
|
||||
if (scrclr_incr)
|
||||
scrclr_pcntr <= scrclr_pcntr + 1'b1;
|
||||
|
||||
/* FSM combinational block */
|
||||
always @(*) begin
|
||||
next = state;
|
||||
|
||||
/* FSM outputs default value */
|
||||
delay_cntr_incr = 1'b0;
|
||||
init_addr_rst = 1'b0;
|
||||
init_addr_incr = 1'b0;
|
||||
scrclr_incr = 1'b0;
|
||||
spi_push = 1'b0;
|
||||
spi_data = '0;
|
||||
spi_disable = 1'b0;
|
||||
spi_do_cmd = 1'b0;
|
||||
spi_do_data = 1'b0;
|
||||
reset_redraw = 1'b0;
|
||||
dflag_clr = 1'b0;
|
||||
next_block = 1'b0;
|
||||
start_write = 1'b0;
|
||||
next_pixel = 1'b0;
|
||||
read_pixel = 1'b0;
|
||||
fb_busy_int = 1'b0;
|
||||
done_o = 1'b0;
|
||||
|
||||
case (state)
|
||||
ST_PREINIT_DELAY: begin
|
||||
delay_cntr_incr = 1'b1;
|
||||
init_addr_rst = 1'b1;
|
||||
|
||||
if (delay_cntr == INIT_DELAY)
|
||||
next = ST_INIT_PUSH_SPI;
|
||||
end
|
||||
|
||||
ST_INIT_PUSH_SPI: begin
|
||||
init_addr_incr = 1'b1;
|
||||
spi_data = init_data[7:0];
|
||||
spi_push = 1'b1;
|
||||
|
||||
{spi_do_cmd, spi_do_data}
|
||||
= init_data[8] ? 2'b01 : 2'b10;
|
||||
|
||||
if (init_addr == (INIT_DATA_SIZE-1))
|
||||
next = ST_INIT_WAIT_LAST;
|
||||
else
|
||||
next = ST_INIT_WAIT_SPI;
|
||||
end
|
||||
|
||||
ST_INIT_WAIT_SPI:
|
||||
if (spi_done)
|
||||
next = ST_INIT_PUSH_SPI;
|
||||
|
||||
ST_INIT_WAIT_LAST:
|
||||
if (spi_done)
|
||||
next = ST_POSTINIT_DELAY;
|
||||
|
||||
ST_POSTINIT_DELAY: begin
|
||||
spi_disable = 1'b1;
|
||||
delay_cntr_incr = 1'b1;
|
||||
|
||||
if (delay_cntr == INIT_DELAY)
|
||||
next = ST_DISPLAY_ON;
|
||||
end
|
||||
|
||||
ST_DISPLAY_ON: begin
|
||||
spi_data = 8'h29;
|
||||
spi_do_cmd = 1'b1;
|
||||
spi_push = 1'b1;
|
||||
|
||||
next = ST_DISPLAY_ONW;
|
||||
end
|
||||
|
||||
ST_DISPLAY_ONW:
|
||||
if (spi_done) begin
|
||||
spi_disable = 1'b1;
|
||||
next = ST_SCRCLR_CMD;
|
||||
end
|
||||
|
||||
ST_SCRCLR_CMD: begin
|
||||
spi_data = 8'h2c;
|
||||
spi_do_cmd = 1'b1;
|
||||
spi_push = 1'b1;
|
||||
next = ST_SCRCLR;
|
||||
end
|
||||
|
||||
ST_SCRCLR:
|
||||
if (spi_done) begin
|
||||
spi_data = 8'h00; //8'h32;
|
||||
spi_do_data = 1'b1;
|
||||
spi_push = 1'b1;
|
||||
scrclr_incr = 1'b1;
|
||||
|
||||
if (scrclr_pcntr ==
|
||||
`ifdef TESTBENCH
|
||||
`ifdef VERILATOR
|
||||
(DISPLAY_MEM_SIZE - 1)
|
||||
`else
|
||||
200
|
||||
`endif
|
||||
`else
|
||||
(DISPLAY_MEM_SIZE - 1)
|
||||
`endif
|
||||
)
|
||||
next = ST_SCRCLR_LAST;
|
||||
end
|
||||
|
||||
ST_SCRCLR_LAST:
|
||||
if (spi_done)
|
||||
next = ST_START_REDRAW;
|
||||
|
||||
ST_START_REDRAW:
|
||||
if (redraw_i) begin
|
||||
spi_disable = 1'b1;
|
||||
reset_redraw = 1'b1;
|
||||
next = ST_READ_FLAG;
|
||||
end
|
||||
|
||||
ST_READ_FLAG:
|
||||
if (is_last_blk) begin
|
||||
done_o = 1'b1;
|
||||
next = ST_START_REDRAW;
|
||||
end
|
||||
else
|
||||
next = ST_CHECK_FLAG;
|
||||
|
||||
ST_CHECK_FLAG:
|
||||
if (dflag_rdata == 1'b1)
|
||||
next = ST_CLEAR_FLAG;
|
||||
else
|
||||
begin
|
||||
next_block = 1'b1;
|
||||
next = ST_READ_FLAG;
|
||||
end
|
||||
|
||||
ST_CLEAR_FLAG: begin
|
||||
dflag_clr = 1'b1;
|
||||
next = ST_CADDR_CMD;
|
||||
end
|
||||
|
||||
ST_CADDR_CMD: begin
|
||||
spi_data = 8'h2a;
|
||||
spi_do_cmd = 1'b1;
|
||||
spi_push = 1'b1;
|
||||
|
||||
next = ST_CADDR_0;
|
||||
end
|
||||
|
||||
ST_CADDR_0:
|
||||
if (spi_done) begin
|
||||
spi_data = caddr_b[15:8];
|
||||
spi_do_data = 1'b1;
|
||||
spi_push = 1'b1;
|
||||
|
||||
next = ST_CADDR_1;
|
||||
end
|
||||
|
||||
ST_CADDR_1:
|
||||
if (spi_done) begin
|
||||
spi_data = caddr_b[7:0];
|
||||
spi_push = 1'b1;
|
||||
|
||||
next = ST_CADDR_2;
|
||||
end
|
||||
|
||||
ST_CADDR_2:
|
||||
if (spi_done) begin
|
||||
spi_data = caddr_e[15:8];
|
||||
spi_push = 1'b1;
|
||||
|
||||
next = ST_CADDR_3;
|
||||
end
|
||||
|
||||
ST_CADDR_3:
|
||||
if (spi_done) begin
|
||||
spi_data = caddr_e[7:0];
|
||||
spi_push = 1'b1;
|
||||
|
||||
next = ST_PADDR_CMD;
|
||||
end
|
||||
|
||||
ST_PADDR_CMD:
|
||||
if (spi_done) begin
|
||||
spi_data = 8'h2b;
|
||||
spi_do_cmd = 1'b1;
|
||||
spi_push = 1'b1;
|
||||
|
||||
next = ST_PADDR_0;
|
||||
end
|
||||
|
||||
ST_PADDR_0:
|
||||
if (spi_done) begin
|
||||
spi_data = paddr_b[15:8];
|
||||
spi_do_data = 1'b1;
|
||||
spi_push = 1'b1;
|
||||
|
||||
next = ST_PADDR_1;
|
||||
end
|
||||
|
||||
ST_PADDR_1:
|
||||
if (spi_done) begin
|
||||
spi_data = paddr_b[7:0];
|
||||
spi_push = 1'b1;
|
||||
|
||||
next = ST_PADDR_2;
|
||||
end
|
||||
|
||||
ST_PADDR_2:
|
||||
if (spi_done) begin
|
||||
spi_data = paddr_e[15:8];
|
||||
spi_push = 1'b1;
|
||||
|
||||
next = ST_PADDR_3;
|
||||
end
|
||||
|
||||
ST_PADDR_3:
|
||||
if (spi_done) begin
|
||||
spi_data = paddr_e[7:0];
|
||||
spi_push = 1'b1;
|
||||
|
||||
next = ST_WRITE_CMD;
|
||||
end
|
||||
|
||||
ST_WRITE_CMD:
|
||||
if (spi_done) begin
|
||||
spi_data = 8'h2c;
|
||||
spi_do_cmd = 1'b1;
|
||||
spi_push = 1'b1;
|
||||
start_write = 1'b1;
|
||||
next = ST_WRITE_CMDW;
|
||||
end
|
||||
|
||||
ST_WRITE_CMDW:
|
||||
if (spi_done)
|
||||
next = ST_FB_READ;
|
||||
|
||||
ST_FB_READ:
|
||||
if (!fb_busy_ext) begin
|
||||
fb_busy_int = 1'b1;
|
||||
next = ST_STORE_PIXEL;
|
||||
end
|
||||
|
||||
ST_STORE_PIXEL: begin
|
||||
fb_busy_int = 1'b1;
|
||||
read_pixel = 1'b1;
|
||||
next = ST_WRITE_PIXEL_H;
|
||||
end
|
||||
|
||||
ST_WRITE_PIXEL_H: begin
|
||||
spi_data = pixel[15:8];
|
||||
spi_do_data = 1'b1;
|
||||
spi_push = 1'b1;
|
||||
next = ST_WRITE_PIXEL_L;
|
||||
end
|
||||
|
||||
ST_WRITE_PIXEL_L:
|
||||
if (spi_done) begin
|
||||
spi_data = pixel[7:0];
|
||||
spi_push = 1'b1;
|
||||
next = ST_NEXT_PIXEL;
|
||||
end
|
||||
|
||||
ST_NEXT_PIXEL:
|
||||
if (spi_done) begin
|
||||
next_pixel = 1'b1;
|
||||
|
||||
if (pi == (BLOCK_SIZE - 1))
|
||||
next = ST_NEXT_BLOCK;
|
||||
else
|
||||
next = ST_FB_READ;
|
||||
end
|
||||
|
||||
ST_NEXT_BLOCK: begin
|
||||
spi_disable = 1'b1;
|
||||
next_block = 1'b1;
|
||||
next = ST_READ_FLAG;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule // lcd_top
|
||||
37
source/lfsr.sv
Normal file
37
source/lfsr.sv
Normal file
@ -0,0 +1,37 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
|
||||
module lfsr #(parameter POLY = 32'hA3000000)
|
||||
(clock,
|
||||
preset,
|
||||
data_i,
|
||||
prnd_o);
|
||||
|
||||
localparam WIDTH = $size(POLY);
|
||||
|
||||
input wire clock;
|
||||
input wire preset;
|
||||
input wire [WIDTH-1:0] data_i;
|
||||
output wire prnd_o;
|
||||
|
||||
logic [WIDTH-1:0] sreg;
|
||||
logic feedback;
|
||||
|
||||
initial sreg = '1;
|
||||
|
||||
assign feedback = sreg[0];
|
||||
assign prnd_o = feedback;
|
||||
|
||||
integer i;
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
if (preset)
|
||||
sreg <= (data_i == '0) ? '1 : data_i;
|
||||
else begin
|
||||
sreg[WIDTH-1] <= feedback;
|
||||
|
||||
for (i = 0; i < (WIDTH-1); i ++)
|
||||
sreg[i] <= POLY[i] ? (sreg[i+1] ^ feedback) : sreg[i+1];
|
||||
end
|
||||
|
||||
endmodule // lfsr
|
||||
133
source/mcp3201_ma.sv
Normal file
133
source/mcp3201_ma.sv
Normal file
@ -0,0 +1,133 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
`include "assert.vh"
|
||||
|
||||
/*
|
||||
* MCP3201 controller
|
||||
* Multichannel and sample rate accurate version.
|
||||
*/
|
||||
module mcp3201_ma #(parameter CHANNELS = 1,
|
||||
parameter CLOCK_FREQ = 12000000,
|
||||
parameter SCLK_FREQ = 1000000,
|
||||
parameter SAMPLE_RATE = 44100)
|
||||
(input wire clock,
|
||||
input wire reset,
|
||||
|
||||
output reg spi_clk_o,
|
||||
output reg spi_ssn_o,
|
||||
input wire [CHANNELS-1:0] spi_miso_i,
|
||||
|
||||
output reg [CHANNELS*12-1:0] data_o,
|
||||
output reg strb_o);
|
||||
|
||||
initial begin
|
||||
`assert(CHANNELS > 0);
|
||||
end
|
||||
|
||||
/* SCLK frequency not need accuracy */
|
||||
localparam SCLK_PERIOD = CLOCK_FREQ/SCLK_FREQ;
|
||||
localparam SCLK_CW = $clog2(SCLK_PERIOD);
|
||||
|
||||
logic [SCLK_CW-1:0] sclk_cnt;
|
||||
logic sclk_posedge;
|
||||
|
||||
/* Make SPI SCLK */
|
||||
always_ff @(posedge clock)
|
||||
if (reset | spi_ssn_o) begin
|
||||
spi_clk_o <= 1'b1;
|
||||
sclk_cnt <= '0;
|
||||
sclk_posedge <= 1'b0;
|
||||
end
|
||||
else begin
|
||||
sclk_posedge <= 1'b0;
|
||||
sclk_cnt <= sclk_cnt + 1'b1;
|
||||
|
||||
if (sclk_cnt == SCLK_CW'(SCLK_PERIOD/2))
|
||||
spi_clk_o <= 1'b0;
|
||||
else
|
||||
if (sclk_cnt == SCLK_CW'(SCLK_PERIOD-1)) begin
|
||||
spi_clk_o <= 1'b1;
|
||||
sclk_cnt <= '0;
|
||||
sclk_posedge <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
/* Sample rate need more accuracy */
|
||||
localparam SRATE_PERIOD = $rtoi($floor($itor(CLOCK_FREQ)/$itor(SAMPLE_RATE) + 0.5));
|
||||
localparam SRATE_CW = $clog2(SRATE_PERIOD);
|
||||
|
||||
logic [SRATE_CW-1:0] srate_cnt;
|
||||
logic sample;
|
||||
|
||||
always_ff @(posedge clock, posedge reset)
|
||||
if (reset) begin
|
||||
sample <= 1'b0;
|
||||
srate_cnt <= '0;
|
||||
end
|
||||
else
|
||||
if (srate_cnt == SRATE_CW'(SRATE_PERIOD-1)) begin
|
||||
sample <= 1'b1;
|
||||
srate_cnt <= '0;
|
||||
end
|
||||
else begin
|
||||
sample <= 1'b0;
|
||||
srate_cnt <= srate_cnt + 1'b1;
|
||||
end
|
||||
|
||||
/* Receive data FSM */
|
||||
enum int unsigned {
|
||||
ST_RELAX = 0,
|
||||
ST_SHIFT,
|
||||
ST_STROBE
|
||||
} state;
|
||||
|
||||
logic [3:0] bit_cnt;
|
||||
logic [11:0] data_sr[CHANNELS];
|
||||
integer i;
|
||||
|
||||
always_ff @(posedge clock, posedge reset)
|
||||
if (reset) begin
|
||||
state <= ST_RELAX;
|
||||
bit_cnt <= '0;
|
||||
spi_ssn_o <= 1'b1;
|
||||
strb_o <= 1'b0;
|
||||
data_o <= '0;
|
||||
|
||||
for (i = 0; i < CHANNELS; i ++)
|
||||
data_sr[i] <= '0;
|
||||
end
|
||||
else begin
|
||||
strb_o <= 1'b0;
|
||||
|
||||
case (state)
|
||||
ST_RELAX:
|
||||
if (sample) begin
|
||||
bit_cnt <= '0;
|
||||
spi_ssn_o <= 1'b0;
|
||||
state <= ST_SHIFT;
|
||||
end
|
||||
|
||||
ST_SHIFT:
|
||||
if (sclk_posedge) begin
|
||||
for (i = 0; i < CHANNELS; i ++)
|
||||
data_sr[i] <= { data_sr[i][10:0], spi_miso_i[i] };
|
||||
|
||||
bit_cnt <= bit_cnt + 1'b1;
|
||||
|
||||
if (bit_cnt == 4'd14) begin
|
||||
spi_ssn_o <= 1'b1;
|
||||
state <= ST_STROBE;
|
||||
end
|
||||
end
|
||||
|
||||
ST_STROBE: begin
|
||||
for (i = 0; i < CHANNELS; i ++)
|
||||
data_o[i*12 +: 12] <= data_sr[i];
|
||||
|
||||
strb_o <= 1'b1;
|
||||
state <= ST_RELAX;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule // mcp3201_ma
|
||||
77
source/pll.sv
Normal file
77
source/pll.sv
Normal file
@ -0,0 +1,77 @@
|
||||
`timescale 1ns/100ps
|
||||
|
||||
/**
|
||||
* PLL configuration 12MHz->30MHz
|
||||
*
|
||||
* F_PLLOUT: 30.000 MHz (requested)
|
||||
* F_PLLOUT: 30.000 MHz (achieved)
|
||||
*
|
||||
* FEEDBACK: SIMPLE
|
||||
* F_PFD: 12.000 MHz
|
||||
* F_VCO: 960.000 MHz
|
||||
*
|
||||
* DIVR: 0 (4'b0000)
|
||||
* DIVF: 79 (7'b1001111)
|
||||
* DIVQ: 5 (3'b101)
|
||||
*
|
||||
* FILTER_RANGE: 1 (3'b001)
|
||||
*/
|
||||
|
||||
`ifdef VERILATOR
|
||||
`define TESTBENCH
|
||||
`endif
|
||||
|
||||
module pll
|
||||
(input clock_in,
|
||||
output clock_out,
|
||||
output locked);
|
||||
|
||||
wire unused_0, unused_1;
|
||||
|
||||
`ifdef TESTBENCH
|
||||
`ifdef VERILATOR
|
||||
/* In Verilator just forward clock_in to clock_out */
|
||||
assign clock_out = clock_in;
|
||||
assign locked = 1'b1;
|
||||
|
||||
`else // !VERILATOR
|
||||
/* In Icarus Verilog generate new clock and 'locked' signal */
|
||||
logic clock_tb;
|
||||
logic lock_tb;
|
||||
|
||||
assign clock_out = clock_tb;
|
||||
assign locked = lock_tb;
|
||||
|
||||
initial begin
|
||||
clock_tb = 1'b0;
|
||||
lock_tb = 1'b0;
|
||||
repeat (100) @(posedge clock_tb);
|
||||
lock_tb = 1'b1;
|
||||
end
|
||||
|
||||
always #(33ns/2) clock_tb <= ~clock_tb;
|
||||
`endif
|
||||
`else
|
||||
/* In HW use PLL primitive */
|
||||
SB_PLL40_PAD #(.FEEDBACK_PATH("SIMPLE"),
|
||||
.DIVR(4'd0),
|
||||
/* For 30 MHz: DIVF=79, DIVQ=5
|
||||
* For 50 MHz: DIVF=66, DIVQ=4 */
|
||||
.DIVF(7'd79),
|
||||
.DIVQ(3'd5),
|
||||
.FILTER_RANGE(3'd1))
|
||||
uut (.PACKAGEPIN (clock_in),
|
||||
.PLLOUTGLOBAL (clock_out),
|
||||
.EXTFEEDBACK (1'b0),
|
||||
.DYNAMICDELAY (8'b0),
|
||||
.LOCK (locked),
|
||||
.BYPASS (1'b0),
|
||||
.RESETB (1'b1),
|
||||
.LATCHINPUTVALUE(1'b0),
|
||||
.PLLOUTCORE (unused_0),
|
||||
.SDO (unused_1),
|
||||
.SDI (1'b0),
|
||||
.SCLK (1'b0));
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
24
source/pll_lock_reset.sv
Normal file
24
source/pll_lock_reset.sv
Normal file
@ -0,0 +1,24 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
`include "assert.vh"
|
||||
|
||||
module pll_lock_reset #(parameter RESET_LEN = 8)
|
||||
(input wire pll_clock,
|
||||
input wire pll_lock,
|
||||
output wire reset);
|
||||
|
||||
initial begin
|
||||
`assert(RESET_LEN > 1);
|
||||
end
|
||||
|
||||
logic [RESET_LEN:0] rst_sr;
|
||||
|
||||
initial rst_sr = '0;
|
||||
|
||||
always_ff @(posedge pll_clock, negedge pll_lock)
|
||||
if (~pll_lock) rst_sr <= '0;
|
||||
else rst_sr <= { 1'b1, rst_sr[RESET_LEN:1] };
|
||||
|
||||
assign reset = ~rst_sr[0];
|
||||
|
||||
endmodule // pll_lock_reset
|
||||
256
source/quadrant_256.rom
Normal file
256
source/quadrant_256.rom
Normal file
@ -0,0 +1,256 @@
|
||||
00ff
|
||||
02ff
|
||||
03ff
|
||||
05ff
|
||||
06ff
|
||||
08ff
|
||||
09ff
|
||||
0bff
|
||||
0dff
|
||||
0eff
|
||||
10ff
|
||||
11fe
|
||||
13fe
|
||||
14fe
|
||||
16fe
|
||||
17fe
|
||||
19fe
|
||||
1bfe
|
||||
1cfd
|
||||
1efd
|
||||
1ffd
|
||||
21fd
|
||||
22fd
|
||||
24fc
|
||||
25fc
|
||||
27fc
|
||||
29fc
|
||||
2afc
|
||||
2cfb
|
||||
2dfb
|
||||
2ffb
|
||||
30fa
|
||||
32fa
|
||||
33fa
|
||||
35f9
|
||||
36f9
|
||||
38f9
|
||||
39f8
|
||||
3bf8
|
||||
3cf8
|
||||
3ef7
|
||||
3ff7
|
||||
41f7
|
||||
43f6
|
||||
44f6
|
||||
46f5
|
||||
47f5
|
||||
49f4
|
||||
4af4
|
||||
4cf4
|
||||
4df3
|
||||
4ff3
|
||||
50f2
|
||||
51f2
|
||||
53f1
|
||||
54f1
|
||||
56f0
|
||||
57f0
|
||||
59ef
|
||||
5aee
|
||||
5cee
|
||||
5ded
|
||||
5fed
|
||||
60ec
|
||||
62ec
|
||||
63eb
|
||||
64ea
|
||||
66ea
|
||||
67e9
|
||||
69e8
|
||||
6ae8
|
||||
6ce7
|
||||
6de7
|
||||
6ee6
|
||||
70e5
|
||||
71e4
|
||||
73e4
|
||||
74e3
|
||||
75e2
|
||||
77e2
|
||||
78e1
|
||||
7ae0
|
||||
7bdf
|
||||
7cdf
|
||||
7ede
|
||||
7fdd
|
||||
80dc
|
||||
82dc
|
||||
83db
|
||||
84da
|
||||
86d9
|
||||
87d8
|
||||
88d7
|
||||
8ad7
|
||||
8bd6
|
||||
8cd5
|
||||
8ed4
|
||||
8fd3
|
||||
90d2
|
||||
92d1
|
||||
93d0
|
||||
94d0
|
||||
95cf
|
||||
97ce
|
||||
98cd
|
||||
99cc
|
||||
9acb
|
||||
9cca
|
||||
9dc9
|
||||
9ec8
|
||||
9fc7
|
||||
a1c6
|
||||
a2c5
|
||||
a3c4
|
||||
a4c3
|
||||
a5c2
|
||||
a7c1
|
||||
a8c0
|
||||
a9bf
|
||||
aabe
|
||||
abbd
|
||||
acbc
|
||||
aebb
|
||||
afba
|
||||
b0b9
|
||||
b1b8
|
||||
b2b7
|
||||
b3b5
|
||||
b4b4
|
||||
b5b3
|
||||
b7b2
|
||||
b8b1
|
||||
b9b0
|
||||
baaf
|
||||
bbae
|
||||
bcac
|
||||
bdab
|
||||
beaa
|
||||
bfa9
|
||||
c0a8
|
||||
c1a7
|
||||
c2a5
|
||||
c3a4
|
||||
c4a3
|
||||
c5a2
|
||||
c6a1
|
||||
c79f
|
||||
c89e
|
||||
c99d
|
||||
ca9c
|
||||
cb9a
|
||||
cc99
|
||||
cd98
|
||||
ce97
|
||||
cf95
|
||||
d094
|
||||
d093
|
||||
d192
|
||||
d290
|
||||
d38f
|
||||
d48e
|
||||
d58c
|
||||
d68b
|
||||
d78a
|
||||
d788
|
||||
d887
|
||||
d986
|
||||
da84
|
||||
db83
|
||||
dc82
|
||||
dc80
|
||||
dd7f
|
||||
de7e
|
||||
df7c
|
||||
df7b
|
||||
e07a
|
||||
e178
|
||||
e277
|
||||
e275
|
||||
e374
|
||||
e473
|
||||
e471
|
||||
e570
|
||||
e66e
|
||||
e76d
|
||||
e76c
|
||||
e86a
|
||||
e869
|
||||
e967
|
||||
ea66
|
||||
ea64
|
||||
eb63
|
||||
ec62
|
||||
ec60
|
||||
ed5f
|
||||
ed5d
|
||||
ee5c
|
||||
ee5a
|
||||
ef59
|
||||
f057
|
||||
f056
|
||||
f154
|
||||
f153
|
||||
f251
|
||||
f250
|
||||
f34f
|
||||
f34d
|
||||
f44c
|
||||
f44a
|
||||
f449
|
||||
f547
|
||||
f546
|
||||
f644
|
||||
f643
|
||||
f741
|
||||
f73f
|
||||
f73e
|
||||
f83c
|
||||
f83b
|
||||
f839
|
||||
f938
|
||||
f936
|
||||
f935
|
||||
fa33
|
||||
fa32
|
||||
fa30
|
||||
fb2f
|
||||
fb2d
|
||||
fb2c
|
||||
fc2a
|
||||
fc29
|
||||
fc27
|
||||
fc25
|
||||
fc24
|
||||
fd22
|
||||
fd21
|
||||
fd1f
|
||||
fd1e
|
||||
fd1c
|
||||
fe1b
|
||||
fe19
|
||||
fe17
|
||||
fe16
|
||||
fe14
|
||||
fe13
|
||||
fe11
|
||||
ff10
|
||||
ff0e
|
||||
ff0d
|
||||
ff0b
|
||||
ff09
|
||||
ff08
|
||||
ff06
|
||||
ff05
|
||||
ff03
|
||||
ff02
|
||||
323
source/sugar_lissajous.sv
Normal file
323
source/sugar_lissajous.sv
Normal file
@ -0,0 +1,323 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
|
||||
/* verilator lint_off UNDRIVEN */
|
||||
/* verilator lint_off UNUSED */
|
||||
|
||||
`define VARIANT_1
|
||||
//`define VARIANT_2
|
||||
|
||||
module sugar_lissajous
|
||||
(input wire CLK12,
|
||||
|
||||
output wire LED_R_N,
|
||||
output wire LED_G_N,
|
||||
output wire LED_B_N,
|
||||
|
||||
// PMOD 1: two ADC MCP3201
|
||||
output wire P1_1, // R SSN
|
||||
input wire P1_2, // --
|
||||
input wire P1_3, // R DAT
|
||||
output wire P1_4, // R CLK
|
||||
output wire P1_9, // L CLK
|
||||
input wire P1_10, // L DAT
|
||||
input wire P1_11, // --
|
||||
output wire P1_12, // L SSN
|
||||
|
||||
// PMOD 2: LCD
|
||||
input wire P2_1, //
|
||||
input wire P2_2, //
|
||||
output wire P2_3, // DC
|
||||
input wire P2_4, //
|
||||
output wire P2_9, // CLK
|
||||
input wire P2_10, //
|
||||
output wire P2_11, // MOSI
|
||||
output wire P2_12 // CSN
|
||||
);
|
||||
|
||||
`ifdef VARIANT_1
|
||||
localparam POINTS_COUNT = 128;
|
||||
localparam POINTS_FADING = 1;
|
||||
localparam DECIMATION = 200;
|
||||
localparam ANGLE_INCREMENT = 8;
|
||||
`elsif VARIANT_2
|
||||
localparam POINTS_COUNT = 32;
|
||||
localparam POINTS_FADING = 0;
|
||||
localparam DECIMATION = 50;
|
||||
localparam ANGLE_INCREMENT = 30;
|
||||
`endif
|
||||
|
||||
assign LED_R_N = 1'b1;
|
||||
assign LED_G_N = 1'b1;
|
||||
assign LED_B_N = 1'b1;
|
||||
|
||||
logic clock;
|
||||
logic reset;
|
||||
logic pll_lock;
|
||||
|
||||
pll pll_i
|
||||
(.clock_in(CLK12),
|
||||
.clock_out(clock),
|
||||
.locked(pll_lock));
|
||||
|
||||
pll_lock_reset #(.RESET_LEN(8)) reset_i
|
||||
(.pll_clock(clock),
|
||||
.pll_lock(pll_lock),
|
||||
.reset(reset));
|
||||
|
||||
localparam SPI_SCLK_FREQ = 1000000;
|
||||
localparam SAMPLE_RATE = 20000;
|
||||
|
||||
logic [11:0] rdata;
|
||||
logic [11:0] ldata;
|
||||
logic strb;
|
||||
|
||||
logic adc_ssn, adc_clk;
|
||||
logic radc_dat, ladc_dat;
|
||||
|
||||
assign P1_1 = adc_ssn;
|
||||
assign P1_4 = adc_clk;
|
||||
assign P1_12 = adc_ssn;
|
||||
assign P1_9 = adc_clk;
|
||||
|
||||
assign radc_dat = P1_3;
|
||||
assign ladc_dat = P1_10;
|
||||
|
||||
/* Grab audio */
|
||||
mcp3201_ma #(.CHANNELS(2),
|
||||
.CLOCK_FREQ(30000000),
|
||||
.SCLK_FREQ(SPI_SCLK_FREQ),
|
||||
.SAMPLE_RATE(SAMPLE_RATE)) adcs_i
|
||||
(.clock, .reset,
|
||||
.spi_clk_o(adc_clk),
|
||||
.spi_ssn_o(adc_ssn),
|
||||
.spi_miso_i({ radc_dat, ladc_dat }),
|
||||
.data_o({ rdata, ldata }),
|
||||
.strb_o(strb));
|
||||
|
||||
/* Filter audio stream */
|
||||
logic [15:0] fir_i;
|
||||
logic [15:0] fir_o;
|
||||
logic fir_i_ready;
|
||||
logic fir_o_valid;
|
||||
|
||||
logic [15:0] fir_abs;
|
||||
logic fir_strb;
|
||||
|
||||
`ifdef TESTBENCH
|
||||
always_ff @ (posedge clock)
|
||||
if (strb) begin
|
||||
fir_abs <= 1024/2;
|
||||
fir_strb <= 1'b1;
|
||||
end
|
||||
else
|
||||
fir_strb <= 1'b0;
|
||||
|
||||
`else // !TESTBENCH
|
||||
|
||||
fir_filter fir_impl
|
||||
(.clock, .reset,
|
||||
.data_i(fir_i),
|
||||
.data_o(fir_o),
|
||||
.ready_i(fir_i_ready),
|
||||
.valid_o(fir_o_valid));
|
||||
|
||||
always_ff @ (posedge clock, posedge reset)
|
||||
if (reset)
|
||||
fir_i_ready <= 1'b0;
|
||||
else
|
||||
if (~fir_i_ready) begin
|
||||
fir_strb <= 1'b0;
|
||||
|
||||
if (strb) begin
|
||||
fir_i <= (ldata >= 1024) ? 16'(ldata) - 16'd1024 : 16'd64512 - 16'(ldata);
|
||||
fir_i_ready <= 1'b1;
|
||||
end
|
||||
end
|
||||
else
|
||||
if (fir_o_valid) begin
|
||||
fir_abs <= fir_o[15] ? 16'hffff - fir_o + 1'b1 : fir_o;
|
||||
fir_i_ready <= 1'b0;
|
||||
fir_strb <= 1'b1;
|
||||
end
|
||||
`endif
|
||||
|
||||
/* Make frame redraw tick */
|
||||
logic tick_redraw;
|
||||
tick_generator #(.PERIOD(600000))
|
||||
tick_refresh_gen (.clock, .reset, .tick_o(tick_redraw));
|
||||
|
||||
logic redraw;
|
||||
logic redraw_done;
|
||||
|
||||
always_ff @ (posedge clock)
|
||||
if (redraw_done)
|
||||
redraw <= 1'b0;
|
||||
else
|
||||
if (tick_redraw)
|
||||
redraw <= 1'b1;
|
||||
|
||||
/* LCD connection */
|
||||
logic spi_csn, spi_clk, spi_sdo, dcn;
|
||||
assign P2_12 = spi_csn;
|
||||
assign P2_9 = spi_clk;
|
||||
assign P2_11 = spi_sdo;
|
||||
assign P2_3 = dcn;
|
||||
|
||||
logic [7:0] lcd_x;
|
||||
logic [8:0] lcd_y;
|
||||
logic lcd_req;
|
||||
logic lcd_ack;
|
||||
logic lcd_wr;
|
||||
|
||||
logic [15:0] color_w;
|
||||
logic [15:0] color_r;
|
||||
|
||||
lcd_top #(.SPI_CLK_PERIOD(4)) lcd_i
|
||||
(.clock, .reset,
|
||||
.lcd_spi_csn_o(spi_csn),
|
||||
.lcd_spi_clk_o(spi_clk),
|
||||
.lcd_spi_dat_o(spi_sdo),
|
||||
.lcd_spi_dcn_o(dcn),
|
||||
.redraw_i(redraw),
|
||||
.done_o(redraw_done),
|
||||
.x_i(lcd_x),
|
||||
.y_i(lcd_y),
|
||||
.color_i(color_w),
|
||||
.color_o(color_r),
|
||||
.req_i(lcd_req),
|
||||
.ack_o(lcd_ack),
|
||||
.wr_i(lcd_wr));
|
||||
|
||||
/* Figure drawer */
|
||||
logic [7:0] fig_x;
|
||||
logic [8:0] fig_y;
|
||||
logic [7:0] fig_h;
|
||||
logic [7:0] fig_s;
|
||||
logic [7:0] fig_v;
|
||||
logic fig_req;
|
||||
logic fig_ack;
|
||||
|
||||
assign lcd_wr = 1'b1;
|
||||
|
||||
fig_drawer fig_i
|
||||
(.clock, .reset,
|
||||
.x_i(fig_x),
|
||||
.y_i(fig_y),
|
||||
.h_i(fig_h),
|
||||
.s_i(fig_s),
|
||||
.v_i(fig_v),
|
||||
.req_i(fig_req),
|
||||
.ack_o(fig_ack),
|
||||
|
||||
.fb_x_o(lcd_x),
|
||||
.fb_y_o(lcd_y),
|
||||
.fb_color_o(color_w),
|
||||
.fb_req_o(lcd_req),
|
||||
.fb_ack_i(lcd_ack));
|
||||
|
||||
/* Awesome circle */
|
||||
logic [9:0] cir_angle;
|
||||
logic [7:0] cir_x;
|
||||
logic [7:0] cir_y;
|
||||
logic cir_req;
|
||||
logic cir_ack;
|
||||
|
||||
circle_1024 DUT
|
||||
(.clock, .reset,
|
||||
.angle(cir_angle),
|
||||
.r(fir_abs[11:4]),
|
||||
.x0(8'd120),
|
||||
.y0(8'd128),
|
||||
.x(cir_x),
|
||||
.y(cir_y),
|
||||
.req_i(cir_req),
|
||||
.ack_o(cir_ack));
|
||||
|
||||
/* Points ring buffer */
|
||||
logic [7:0] pt_x;
|
||||
logic [7:0] pt_y;
|
||||
logic [7:0] pt_h;
|
||||
logic pt_req;
|
||||
logic pt_ack;
|
||||
|
||||
fig_ring #(.POINT_COUNT(POINTS_COUNT),
|
||||
.FADING(POINTS_FADING)) fig_ring_i
|
||||
(.clock, .reset,
|
||||
.pt_x(pt_x),
|
||||
.pt_y(pt_y),
|
||||
.pt_h(pt_h),
|
||||
.pt_req_i(pt_req),
|
||||
.pt_ack_o(pt_ack),
|
||||
|
||||
.fig_x_o(fig_x),
|
||||
.fig_y_o(fig_y),
|
||||
.fig_h_o(fig_h),
|
||||
.fig_s_o(fig_s),
|
||||
.fig_v_o(fig_v),
|
||||
.fig_req_o(fig_req),
|
||||
.fig_ack_i(fig_ack));
|
||||
|
||||
/* Decimate audio stream */
|
||||
localparam DECIMATION_CW = $clog2(DECIMATION);
|
||||
|
||||
logic [DECIMATION_CW-1:0] decim_cntr;
|
||||
logic decim_strobe;
|
||||
|
||||
always_ff @ (posedge clock, posedge reset)
|
||||
if (reset)
|
||||
decim_cntr <= '0;
|
||||
else
|
||||
if (decim_cntr == (DECIMATION-1)) begin
|
||||
decim_cntr <= '0;
|
||||
decim_strobe <= 1'b1;
|
||||
end
|
||||
else begin
|
||||
decim_strobe <= 1'b0;
|
||||
|
||||
if (fir_strb)
|
||||
decim_cntr <= decim_cntr + 1'b1;
|
||||
end
|
||||
|
||||
/* Draw autio sample on circle */
|
||||
enum int unsigned {
|
||||
ST_FIG_IDLE = 0,
|
||||
ST_FIG_CIRCLE,
|
||||
ST_FIG_DRAW
|
||||
} state_fig;
|
||||
|
||||
always_ff @ (posedge clock, posedge reset)
|
||||
if (reset) begin
|
||||
state_fig <= ST_FIG_IDLE;
|
||||
cir_req <= 1'b0;
|
||||
pt_req <= 1'b0;
|
||||
cir_angle <= '0;
|
||||
pt_h <= '0;
|
||||
end
|
||||
else
|
||||
case (state_fig)
|
||||
ST_FIG_IDLE:
|
||||
if (decim_strobe) begin
|
||||
cir_req <= 1'b1;
|
||||
state_fig <= ST_FIG_CIRCLE;
|
||||
end
|
||||
|
||||
ST_FIG_CIRCLE:
|
||||
if (cir_ack) begin
|
||||
cir_req <= 1'b0;
|
||||
pt_x <= cir_x;
|
||||
pt_y <= cir_y;
|
||||
pt_req <= 1'b1;
|
||||
state_fig <= ST_FIG_DRAW;
|
||||
end
|
||||
|
||||
ST_FIG_DRAW:
|
||||
if (pt_ack) begin
|
||||
pt_req <= 1'b0;
|
||||
cir_angle <= cir_angle + ANGLE_INCREMENT;
|
||||
pt_h <= pt_h + 1'b1;
|
||||
state_fig <= ST_FIG_IDLE;
|
||||
end
|
||||
endcase
|
||||
|
||||
endmodule // sugar_lissajous
|
||||
33
source/tick_generator.sv
Normal file
33
source/tick_generator.sv
Normal file
@ -0,0 +1,33 @@
|
||||
`timescale 1ns/100ps
|
||||
`default_nettype none
|
||||
`include "assert.vh"
|
||||
|
||||
module tick_generator #(parameter PERIOD = 1000)
|
||||
(input wire clock,
|
||||
input wire reset,
|
||||
output reg tick_o);
|
||||
|
||||
initial begin
|
||||
`assert(PERIOD > 1);
|
||||
end
|
||||
|
||||
localparam TICK_CW = $clog2(PERIOD);
|
||||
logic [TICK_CW-1:0] cntr;
|
||||
|
||||
always_ff @(posedge clock, posedge reset)
|
||||
if (reset) begin
|
||||
cntr <= '0;
|
||||
tick_o <= 1'b0;
|
||||
end
|
||||
else begin
|
||||
if (cntr == (PERIOD-1)) begin
|
||||
cntr <= '0;
|
||||
tick_o <= 1'b1;
|
||||
end
|
||||
else begin
|
||||
cntr <= cntr + 1'b1;
|
||||
tick_o <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule // tick_generator
|
||||
5
testbench/.dir-locals.el
Normal file
5
testbench/.dir-locals.el
Normal 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
5
testbench/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
*.out
|
||||
*.bin
|
||||
*.vcd
|
||||
*.gtkw
|
||||
filtered.txt
|
||||
31
testbench/Makefile
Normal file
31
testbench/Makefile
Normal 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
|
||||
1
testbench/fig_circle_8x8.rom
Symbolic link
1
testbench/fig_circle_8x8.rom
Symbolic link
@ -0,0 +1 @@
|
||||
../source/fig_circle_8x8.rom
|
||||
9
testbench/fir-magn.m
Normal file
9
testbench/fir-magn.m
Normal 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)));
|
||||
1
testbench/fir_425_50hz_100hz_0db_40db.rom
Symbolic link
1
testbench/fir_425_50hz_100hz_0db_40db.rom
Symbolic link
@ -0,0 +1 @@
|
||||
../source/fir_425_50hz_100hz_0db_40db.rom
|
||||
2
testbench/lcd-model/.clang_complete
Normal file
2
testbench/lcd-model/.clang_complete
Normal file
@ -0,0 +1,2 @@
|
||||
-I./obj_dir
|
||||
-I/usr/share/verilator/include
|
||||
5
testbench/lcd-model/.dir-locals.el
Normal file
5
testbench/lcd-model/.dir-locals.el
Normal 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
2
testbench/lcd-model/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
obj_dir
|
||||
*.vcd
|
||||
31
testbench/lcd-model/Makefile
Normal file
31
testbench/lcd-model/Makefile
Normal 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
|
||||
1
testbench/lcd-model/fig_circle_8x8.rom
Symbolic link
1
testbench/lcd-model/fig_circle_8x8.rom
Symbolic link
@ -0,0 +1 @@
|
||||
../../source/fig_circle_8x8.rom
|
||||
80
testbench/lcd-model/frontend.rkt
Executable file
80
testbench/lcd-model/frontend.rkt
Executable 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)))))
|
||||
156
testbench/lcd-model/lcd_ili9341_4spi.sv
Normal file
156
testbench/lcd-model/lcd_ili9341_4spi.sv
Normal 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
|
||||
61
testbench/lcd-model/lcd_init.rom
Normal file
61
testbench/lcd-model/lcd_init.rom
Normal 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
|
||||
1
testbench/lcd-model/quadrant_256.rom
Symbolic link
1
testbench/lcd-model/quadrant_256.rom
Symbolic link
@ -0,0 +1 @@
|
||||
../../source/quadrant_256.rom
|
||||
107
testbench/lcd-model/testbench_top.cpp
Normal file
107
testbench/lcd-model/testbench_top.cpp
Normal 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;
|
||||
}
|
||||
41
testbench/lcd-model/testbench_top.sv
Normal file
41
testbench/lcd-model/testbench_top.sv
Normal 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
1
testbench/lcd_init.rom
Symbolic link
@ -0,0 +1 @@
|
||||
../source/lcd_init.rom
|
||||
1
testbench/quadrant_256.rom
Symbolic link
1
testbench/quadrant_256.rom
Symbolic link
@ -0,0 +1 @@
|
||||
../source/quadrant_256.rom
|
||||
60
testbench/tb_circle.sv
Normal file
60
testbench/tb_circle.sv
Normal 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
|
||||
70
testbench/tb_fig_drawer.sv
Normal file
70
testbench/tb_fig_drawer.sv
Normal 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
69
testbench/tb_fig_ring.sv
Normal 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
|
||||
66
testbench/tb_fir_filter.sv
Normal file
66
testbench/tb_fir_filter.sv
Normal 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
49
testbench/tb_hsl2rgb.sv
Normal 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
78
testbench/tb_hsv2rgb.sv
Normal 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
63
testbench/tb_lcd_spi.sv
Normal 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
|
||||
Loading…
x
Reference in New Issue
Block a user