blob: 68b11c9ffb12e62201feaf3521e2b63720cc4c5d [file] [log] [blame]
// Copyright 2020 Matt Aamold, James Aamold
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Language: Verilog 2001
`timescale 1ns / 1ps
module spi (
input wire SPI_CLK,
input wire RST,
input wire SCLK,
input wire SCSN,
input wire MOSI,
output reg start_of_transfer,
output reg end_of_transfer,
output reg [7:0] mosi_data_out,
output reg mosi_data_ready,
output reg MISO,
output reg miso_data_request,
input [7:0] miso_data_in
);
// //////////////////////////////////////////////////////
// synchronizers
reg [1:0] scsn_resync;
reg [1:0] sclk_resync;
reg [1:0] mosi_resync;
reg [1:0] scsn_edge;
reg [1:0] sclk_edge;
wire scsn_rs;
wire mosi_rs;
reg rising_sclk;
reg falling_sclk;
always @(posedge SPI_CLK)
if (RST) begin
sclk_resync <= 0;
sclk_edge <= 'h0;
scsn_resync <= 'h3;
scsn_edge <= 'h3;
mosi_resync <= 0;
end
else begin
scsn_resync <= {scsn_resync[0], SCSN};
scsn_edge <= {scsn_edge[0], scsn_resync[1]};
sclk_resync <= {sclk_resync[0], SCLK};
sclk_edge <= {sclk_edge[0], sclk_resync[1]};
mosi_resync <= {mosi_resync[0], MOSI};
end
assign scsn_rs = scsn_resync[1];
assign mosi_rs = mosi_resync[1];
always @(posedge SPI_CLK)
if (RST) begin
rising_sclk <= 0;
falling_sclk <= 0;
start_of_transfer <= 0;
end_of_transfer <= 0;
end
else begin
rising_sclk <= !sclk_edge[1] & sclk_edge[0] & !scsn_rs;
falling_sclk <= sclk_edge[1] & !sclk_edge[0] & !scsn_rs;
start_of_transfer <= scsn_edge[1] & !scsn_edge[0];
end_of_transfer <= !scsn_edge[1] & scsn_edge[0];
end
// //////////////////////////////////////////////////////
// strobes
reg [2:0] bitcount;
reg byteCountStrobe;
always @(posedge SPI_CLK)
if (RST) begin
bitcount <= 0;
byteCountStrobe <= 0;
end
else if (start_of_transfer) begin
bitcount <= 0;
byteCountStrobe <= 0;
end
else if (falling_sclk) begin
bitcount <= bitcount + 1'b1;
byteCountStrobe <= (bitcount == 'h7);
end
else if (byteCountStrobe | scsn_rs)
byteCountStrobe <= 0;
// //////////////////////////////////////////////////////
// MOSI snapshot register and output
reg [7:0] mosi_data_shift_reg;
always @(posedge SPI_CLK)
if (RST) begin
mosi_data_shift_reg <= 0;
end
else if (rising_sclk) begin
mosi_data_shift_reg <= {mosi_data_shift_reg[6:0], mosi_rs};
end
always @(posedge SPI_CLK)
if (RST) begin
mosi_data_out <= 0;
end
else if (byteCountStrobe) begin
mosi_data_out <= mosi_data_shift_reg;
end
always @(posedge SPI_CLK)
if (RST)
mosi_data_ready <= 0;
else
mosi_data_ready <= byteCountStrobe;
// //////////////////////////////////////////////////////
// MISO input capture and presentation to host
reg [7:0] miso_data_shift_reg;
always @(posedge SPI_CLK)
if (RST)
miso_data_request <= 0;
else
miso_data_request <= byteCountStrobe;
always @(posedge SPI_CLK)
if (RST) begin
miso_data_shift_reg <= 0;
end
else if (miso_data_request) begin
miso_data_shift_reg <= miso_data_in;
end
else if (falling_sclk)
miso_data_shift_reg <= {miso_data_shift_reg[6:0], 1'b0};
always @(posedge SPI_CLK)
if (RST)
MISO <= 0;
else
MISO <= miso_data_shift_reg[7];
endmodule // spi