sugar-lissajous/source/sugar_lissajous.sv
2021-02-28 18:59:56 +03:00

324 lines
7.4 KiB
Systemverilog

`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