248 lines
8.6 KiB
Systemverilog
248 lines
8.6 KiB
Systemverilog
/*
|
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
|
|
|
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.
|
|
*/
|
|
|
|
module spi_core #(
|
|
parameter int unsigned TX_FIFO_DEPTH = 8,
|
|
parameter int unsigned RX_FIFO_DEPTH = 8
|
|
)(
|
|
input logic clk_i,
|
|
input logic rst_ni,
|
|
|
|
// SPI引脚信号
|
|
input logic spi_clk_i,
|
|
output logic spi_clk_o,
|
|
output logic spi_clk_oe_o,
|
|
input logic spi_ss_i,
|
|
output logic spi_ss_o,
|
|
output logic spi_ss_oe_o,
|
|
input logic spi_dq0_i,
|
|
output logic spi_dq0_o,
|
|
output logic spi_dq0_oe_o,
|
|
input logic spi_dq1_i,
|
|
output logic spi_dq1_o,
|
|
output logic spi_dq1_oe_o,
|
|
input logic spi_dq2_i,
|
|
output logic spi_dq2_o,
|
|
output logic spi_dq2_oe_o,
|
|
input logic spi_dq3_i,
|
|
output logic spi_dq3_o,
|
|
output logic spi_dq3_oe_o,
|
|
|
|
// 中断信号
|
|
output logic irq_o,
|
|
|
|
// OBI总线接口信号
|
|
input logic reg_we_i,
|
|
input logic reg_re_i,
|
|
input logic [31:0] reg_wdata_i,
|
|
input logic [ 3:0] reg_be_i,
|
|
input logic [31:0] reg_addr_i,
|
|
output logic [31:0] reg_rdata_o
|
|
);
|
|
|
|
import spi_reg_pkg::*;
|
|
|
|
parameter int unsigned TX_FIFO_ADDR_DEPTH = (TX_FIFO_DEPTH > 1) ? $clog2(TX_FIFO_DEPTH) : 1;
|
|
parameter int unsigned RX_FIFO_ADDR_DEPTH = (RX_FIFO_DEPTH > 1) ? $clog2(RX_FIFO_DEPTH) : 1;
|
|
|
|
spi_reg_pkg::spi_reg2hw_t reg2hw;
|
|
spi_reg_pkg::spi_hw2reg_t hw2reg;
|
|
|
|
logic [TX_FIFO_ADDR_DEPTH-1:0] tx_fifo_usage;
|
|
logic [RX_FIFO_ADDR_DEPTH-1:0] rx_fifo_usage;
|
|
|
|
logic master_enable;
|
|
logic master_start;
|
|
logic master_ready, master_ready_re, master_ready_fe;
|
|
logic master_read;
|
|
logic master_msb_first;
|
|
logic master_data_valid, master_data_valid_re;
|
|
logic master_ss_sw_ctrl;
|
|
logic master_ss_level;
|
|
logic busy_q;
|
|
logic [2:0] master_clk_div;
|
|
logic [1:0] master_cp_mode;
|
|
logic [1:0] master_spi_mode;
|
|
logic [3:0] master_ss_delay_cnt;
|
|
logic [7:0] master_data_out;
|
|
logic tx_fifo_full;
|
|
logic tx_fifo_empty;
|
|
logic [7:0] tx_fifo_data_in;
|
|
logic tx_fifo_push;
|
|
logic [7:0] tx_fifo_data_out;
|
|
logic tx_fifo_pop;
|
|
logic tx_fifo_flush;
|
|
logic rx_fifo_full;
|
|
logic rx_fifo_empty;
|
|
logic [7:0] rx_fifo_data_in;
|
|
logic rx_fifo_push;
|
|
logic [7:0] rx_fifo_data_out;
|
|
logic rx_fifo_pop;
|
|
logic rx_fifo_flush;
|
|
|
|
assign master_enable = ~reg2hw.ctrl0.role_mode.q;
|
|
assign master_start = reg2hw.ctrl0.enable.q && (!tx_fifo_empty);
|
|
assign master_read = reg2hw.ctrl0.read.q;
|
|
assign master_msb_first = reg2hw.ctrl0.msb_first.q;
|
|
assign master_clk_div = reg2hw.ctrl0.clk_div.q;
|
|
assign master_cp_mode = reg2hw.ctrl0.cp_mode.q;
|
|
assign master_spi_mode = reg2hw.ctrl0.spi_mode.q;
|
|
assign master_ss_delay_cnt = reg2hw.ctrl0.ss_delay.q;
|
|
assign master_ss_sw_ctrl = reg2hw.ctrl0.ss_sw_ctrl.q;
|
|
assign master_ss_level = reg2hw.ctrl0.ss_level.q;
|
|
|
|
assign tx_fifo_push = reg2hw.txdata.qe;
|
|
assign tx_fifo_data_in = reg2hw.txdata.q[7:0];
|
|
assign tx_fifo_pop = master_data_valid_re | master_ready_fe;
|
|
assign tx_fifo_flush = reg2hw.ctrl0.tx_fifo_reset.q && reg2hw.ctrl0.tx_fifo_reset.qe;
|
|
// 读操作才把接收到的数据压入RX FIFO
|
|
assign rx_fifo_push = master_data_valid_re & master_read;
|
|
assign rx_fifo_data_in = master_data_out;
|
|
assign rx_fifo_pop = reg2hw.rxdata.re;
|
|
assign hw2reg.rxdata.d = {24'h0, rx_fifo_data_out};
|
|
assign rx_fifo_flush = reg2hw.ctrl0.rx_fifo_reset.q && reg2hw.ctrl0.rx_fifo_reset.qe;
|
|
|
|
assign hw2reg.status.tx_fifo_full.d = tx_fifo_full;
|
|
assign hw2reg.status.tx_fifo_empty.d = tx_fifo_empty;
|
|
assign hw2reg.status.rx_fifo_full.d = rx_fifo_full;
|
|
assign hw2reg.status.rx_fifo_empty.d = rx_fifo_empty;
|
|
// 传输完成置位中断pending
|
|
assign hw2reg.ctrl0.int_pending.d = 1'b1;
|
|
assign hw2reg.ctrl0.int_pending.de = master_enable & master_ready_re & reg2hw.ctrl0.int_en.q;
|
|
// 传输完成清零busy位
|
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
|
if (!rst_ni) begin
|
|
busy_q <= 1'b0;
|
|
end else begin
|
|
if (master_start) begin
|
|
busy_q <= 1'b1;
|
|
end else if (master_enable & master_ready_re) begin
|
|
busy_q <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
assign hw2reg.status.busy.d = busy_q;
|
|
|
|
// 中断信号
|
|
assign irq_o = reg2hw.ctrl0.int_pending.q;
|
|
|
|
edge_detect #(
|
|
.DP(0)
|
|
) master_data_valid_ed (
|
|
.clk_i(clk_i),
|
|
.rst_ni(rst_ni),
|
|
.sig_i(master_data_valid),
|
|
.sig_o(),
|
|
.re_o(master_data_valid_re),
|
|
.fe_o()
|
|
);
|
|
|
|
edge_detect #(
|
|
.DP(0)
|
|
) master_ready_ed (
|
|
.clk_i(clk_i),
|
|
.rst_ni(rst_ni),
|
|
.sig_i(master_ready),
|
|
.sig_o(),
|
|
.re_o(master_ready_re),
|
|
.fe_o(master_ready_fe)
|
|
);
|
|
|
|
// TX FIFO
|
|
sync_fifo #(
|
|
.DATA_WIDTH(8),
|
|
.DEPTH(TX_FIFO_DEPTH)
|
|
) u_tx_fifo (
|
|
.clk_i (clk_i),
|
|
.rst_ni (rst_ni),
|
|
.flush_i (tx_fifo_flush),
|
|
.testmode_i (1'b0),
|
|
.full_o (tx_fifo_full),
|
|
.empty_o (tx_fifo_empty),
|
|
.usage_o (tx_fifo_usage),
|
|
.data_i (tx_fifo_data_in),
|
|
.push_i (tx_fifo_push),
|
|
.data_o (tx_fifo_data_out),
|
|
.pop_i (tx_fifo_pop)
|
|
);
|
|
|
|
// RX FIFO
|
|
sync_fifo #(
|
|
.DATA_WIDTH(8),
|
|
.DEPTH(RX_FIFO_DEPTH)
|
|
) u_rx_fifo (
|
|
.clk_i (clk_i),
|
|
.rst_ni (rst_ni),
|
|
.flush_i (rx_fifo_flush),
|
|
.testmode_i (1'b0),
|
|
.full_o (rx_fifo_full),
|
|
.empty_o (rx_fifo_empty),
|
|
.usage_o (rx_fifo_usage),
|
|
.data_i (rx_fifo_data_in),
|
|
.push_i (rx_fifo_push),
|
|
.data_o (rx_fifo_data_out),
|
|
.pop_i (rx_fifo_pop)
|
|
);
|
|
|
|
spi_master u_spi_master (
|
|
.clk_i (clk_i),
|
|
.rst_ni (rst_ni),
|
|
.start_i (master_start),
|
|
.read_i (master_read),
|
|
.data_i (tx_fifo_data_out),
|
|
.spi_mode_i (master_spi_mode),
|
|
.cp_mode_i (master_cp_mode),
|
|
.div_ratio_i (master_clk_div),
|
|
.msb_first_i (master_msb_first),
|
|
.ss_delay_cnt_i(master_ss_delay_cnt),
|
|
.ss_sw_ctrl_i (master_ss_sw_ctrl),
|
|
.ss_level_i (master_ss_level),
|
|
.data_o (master_data_out),
|
|
.ready_o (master_ready),
|
|
.data_valid_o (master_data_valid),
|
|
.spi_clk_o (spi_clk_o),
|
|
.spi_clk_oe_o (spi_clk_oe_o),
|
|
.spi_ss_o (spi_ss_o),
|
|
.spi_ss_oe_o (spi_ss_oe_o),
|
|
.spi_dq0_i (spi_dq0_i),
|
|
.spi_dq0_o (spi_dq0_o),
|
|
.spi_dq0_oe_o (spi_dq0_oe_o),
|
|
.spi_dq1_i (spi_dq1_i),
|
|
.spi_dq1_o (spi_dq1_o),
|
|
.spi_dq1_oe_o (spi_dq1_oe_o),
|
|
.spi_dq2_i (spi_dq2_i),
|
|
.spi_dq2_o (spi_dq2_o),
|
|
.spi_dq2_oe_o (spi_dq2_oe_o),
|
|
.spi_dq3_i (spi_dq3_i),
|
|
.spi_dq3_o (spi_dq3_o),
|
|
.spi_dq3_oe_o (spi_dq3_oe_o)
|
|
);
|
|
|
|
spi_reg_top u_spi_reg_top (
|
|
.clk_i (clk_i),
|
|
.rst_ni (rst_ni),
|
|
.reg2hw (reg2hw),
|
|
.hw2reg (hw2reg),
|
|
.reg_we (reg_we_i),
|
|
.reg_re (reg_re_i),
|
|
.reg_wdata (reg_wdata_i),
|
|
.reg_be (reg_be_i),
|
|
.reg_addr (reg_addr_i),
|
|
.reg_rdata (reg_rdata_o)
|
|
);
|
|
|
|
endmodule
|