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

99 lines
2.3 KiB
Systemverilog

`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