rtl:perips: add spi master
Signed-off-by: liangkangnan <liangkangnan@163.com>pull/4/head
parent
f74f2d8f5d
commit
57690b00bd
|
@ -30,6 +30,30 @@ set_property PACKAGE_PIN R10 [get_ports i2c_scl_pin]
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports i2c_sda_pin]
|
set_property IOSTANDARD LVCMOS33 [get_ports i2c_sda_pin]
|
||||||
set_property PACKAGE_PIN R11 [get_ports i2c_sda_pin]
|
set_property PACKAGE_PIN R11 [get_ports i2c_sda_pin]
|
||||||
|
|
||||||
|
# SPI DQ3引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports spi_dq3_pin]
|
||||||
|
set_property PACKAGE_PIN P3 [get_ports spi_dq3_pin]
|
||||||
|
|
||||||
|
# SPI DQ2引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports spi_dq2_pin]
|
||||||
|
set_property PACKAGE_PIN P4 [get_ports spi_dq2_pin]
|
||||||
|
|
||||||
|
# SPI DQ1引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports spi_dq1_pin]
|
||||||
|
set_property PACKAGE_PIN P1 [get_ports spi_dq1_pin]
|
||||||
|
|
||||||
|
# SPI DQ0引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports spi_dq0_pin]
|
||||||
|
set_property PACKAGE_PIN N1 [get_ports spi_dq0_pin]
|
||||||
|
|
||||||
|
# SPI SS引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports spi_ss_pin]
|
||||||
|
set_property PACKAGE_PIN M5 [get_ports spi_ss_pin]
|
||||||
|
|
||||||
|
# SPI CLK引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports spi_clk_pin]
|
||||||
|
set_property PACKAGE_PIN N4 [get_ports spi_clk_pin]
|
||||||
|
|
||||||
# GPIO0引脚
|
# GPIO0引脚
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_pins[0]}]
|
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_pins[0]}]
|
||||||
set_property PACKAGE_PIN P16 [get_ports {gpio_pins[0]}]
|
set_property PACKAGE_PIN P16 [get_ports {gpio_pins[0]}]
|
||||||
|
|
|
@ -59,6 +59,12 @@
|
||||||
../rtl/perips/i2c/i2c_top.sv
|
../rtl/perips/i2c/i2c_top.sv
|
||||||
../rtl/perips/i2c/i2c_master.sv
|
../rtl/perips/i2c/i2c_master.sv
|
||||||
../rtl/perips/i2c/i2c_slave.sv
|
../rtl/perips/i2c/i2c_slave.sv
|
||||||
|
../rtl/perips/spi/spi_reg_pkg.sv
|
||||||
|
../rtl/perips/spi/spi_reg_top.sv
|
||||||
|
../rtl/perips/spi/spi_core.sv
|
||||||
|
../rtl/perips/spi/spi_top.sv
|
||||||
|
../rtl/perips/spi/spi_master.sv
|
||||||
|
../rtl/perips/spi/spi_transmit_byte.sv
|
||||||
|
|
||||||
../rtl/sys_bus/obi_interconnect.sv
|
../rtl/sys_bus/obi_interconnect.sv
|
||||||
../rtl/sys_bus/obi_interconnect_master_sel.sv
|
../rtl/sys_bus/obi_interconnect_master_sel.sv
|
||||||
|
|
|
@ -43,6 +43,9 @@
|
||||||
// I2C0
|
// I2C0
|
||||||
`define I2C0_ADDR_MASK ~32'hffff
|
`define I2C0_ADDR_MASK ~32'hffff
|
||||||
`define I2C0_ADDR_BASE 32'h60000000
|
`define I2C0_ADDR_BASE 32'h60000000
|
||||||
|
// SPI0
|
||||||
|
`define SPI0_ADDR_MASK ~32'hffff
|
||||||
|
`define SPI0_ADDR_BASE 32'h70000000
|
||||||
// Interrupt controller
|
// Interrupt controller
|
||||||
`define RVIC_ADDR_MASK ~32'hffff
|
`define RVIC_ADDR_MASK ~32'hffff
|
||||||
`define RVIC_ADDR_BASE 32'hD0000000
|
`define RVIC_ADDR_BASE 32'hD0000000
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
// Copyright lowRISC contributors.
|
||||||
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
{ name: "spi",
|
||||||
|
clocking: [{clock: "clk_i", reset: "rst_ni"}],
|
||||||
|
bus_interfaces: [
|
||||||
|
{ protocol: "tlul", direction: "device" }
|
||||||
|
],
|
||||||
|
regwidth: "32",
|
||||||
|
registers: [
|
||||||
|
{ name: "CTRL0",
|
||||||
|
desc: "SPI control 0 register",
|
||||||
|
swaccess: "rw",
|
||||||
|
hwaccess: "hrw",
|
||||||
|
hwqe: "true",
|
||||||
|
fields: [
|
||||||
|
{ bits: "0",
|
||||||
|
name: "ENABLE",
|
||||||
|
desc: "SPI enable",
|
||||||
|
}
|
||||||
|
{ bits: "1",
|
||||||
|
name: "INT_EN",
|
||||||
|
desc: "SPI interrupt enable",
|
||||||
|
}
|
||||||
|
{ bits: "2",
|
||||||
|
name: "INT_PENDING",
|
||||||
|
swaccess: "rw1c",
|
||||||
|
desc: "SPI master transmit completely interrupt pending",
|
||||||
|
}
|
||||||
|
{ bits: "3",
|
||||||
|
name: "ROLE_MODE",
|
||||||
|
desc: "SPI role mode, 0: master, 1: slave",
|
||||||
|
}
|
||||||
|
{ bits: "5:4",
|
||||||
|
name: "CP_MODE",
|
||||||
|
desc: "SPI CPOL and CPHA mode",
|
||||||
|
}
|
||||||
|
{ bits: "7:6",
|
||||||
|
name: "SPI_MODE",
|
||||||
|
desc: "0: normal, 1: dual, 2: quad",
|
||||||
|
}
|
||||||
|
{ bits: "8",
|
||||||
|
name: "READ",
|
||||||
|
desc: "0: write, 1: read",
|
||||||
|
}
|
||||||
|
{ bits: "9",
|
||||||
|
name: "MSB_FIRST",
|
||||||
|
desc: "0: lsb, 1: msb",
|
||||||
|
}
|
||||||
|
{ bits: "10",
|
||||||
|
name: "SS_SW_CTRL",
|
||||||
|
desc: "ss ctrl by software. 0: hw, 1: sw",
|
||||||
|
}
|
||||||
|
{ bits: "11",
|
||||||
|
name: "SS_LEVEL",
|
||||||
|
desc: "ss output level. valid only when bit[10]=1",
|
||||||
|
}
|
||||||
|
{ bits: "15:12",
|
||||||
|
name: "SS_DELAY",
|
||||||
|
desc: "SPI ss signal active or inactive how many spi clk",
|
||||||
|
}
|
||||||
|
{ bits: "31:29",
|
||||||
|
name: "CLK_DIV",
|
||||||
|
desc: "SPI clock divider count",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{ name: "STATUS",
|
||||||
|
desc: "SPI status register",
|
||||||
|
swaccess: "ro"
|
||||||
|
hwaccess: "hrw"
|
||||||
|
hwext: "true"
|
||||||
|
fields: [
|
||||||
|
{ bits: "0",
|
||||||
|
name: "TX_FIFO_FULL",
|
||||||
|
desc: "tx fifo is full",
|
||||||
|
}
|
||||||
|
{ bits: "1",
|
||||||
|
name: "TX_FIFO_EMPTY",
|
||||||
|
desc: "tx fifo is empty",
|
||||||
|
}
|
||||||
|
{ bits: "2",
|
||||||
|
name: "RX_FIFO_FULL",
|
||||||
|
desc: "rx fifo is full",
|
||||||
|
}
|
||||||
|
{ bits: "3",
|
||||||
|
name: "RX_FIFO_EMPTY",
|
||||||
|
desc: "rx fifo is empty",
|
||||||
|
}
|
||||||
|
{ bits: "4",
|
||||||
|
name: "BUSY",
|
||||||
|
desc: "SPI is transmitting or nor, 0: IDLE, 1: BUSY",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{ name: "TXDATA",
|
||||||
|
desc: "SPI TX data register",
|
||||||
|
swaccess: "wo",
|
||||||
|
hwaccess: "hro",
|
||||||
|
hwqe: "true",
|
||||||
|
fields: [
|
||||||
|
{ bits: "7:0" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{ name: "RXDATA",
|
||||||
|
desc: "SPI RX data register",
|
||||||
|
swaccess: "ro",
|
||||||
|
hwaccess: "hrw",
|
||||||
|
hwext: "true",
|
||||||
|
hwre: "true",
|
||||||
|
fields: [
|
||||||
|
{ bits: "7:0" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,243 @@
|
||||||
|
/*
|
||||||
|
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 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
assign tx_fifo_pop = master_data_valid_re | master_ready_fe;
|
||||||
|
// 读操作才把接收到的数据压入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 = rx_fifo_data_out;
|
||||||
|
|
||||||
|
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 (1'b0),
|
||||||
|
.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 (1'b0),
|
||||||
|
.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
|
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
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_master (
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_ni,
|
||||||
|
|
||||||
|
input logic start_i, // 开始传输
|
||||||
|
input logic read_i, // 0: write, 1: read
|
||||||
|
input logic [7:0] data_i, // 字节输入
|
||||||
|
input logic [1:0] spi_mode_i, // 0: SPI, 1: Dual SPI, 2: Quad SPI, 3: SPI
|
||||||
|
input logic [1:0] cp_mode_i, // [1]表示CPOL, [0]表示CPHA
|
||||||
|
input logic [2:0] div_ratio_i, // 分频比
|
||||||
|
input logic msb_first_i, // 1: MSB, 0: LSB
|
||||||
|
input logic [3:0] ss_delay_cnt_i, // SS信号延时时钟个数
|
||||||
|
input logic ss_sw_ctrl_i, // 软件控制SS信号
|
||||||
|
input logic ss_level_i, // SS输出电平,仅当ss_sw_ctrl_i=1时有效
|
||||||
|
output logic [7:0] data_o, // 接收到的数据
|
||||||
|
output logic ready_o, // 1: IDLE, 0: 正在传输
|
||||||
|
output logic data_valid_o, // 接收到的数据有效
|
||||||
|
|
||||||
|
// CLK
|
||||||
|
output logic spi_clk_o,
|
||||||
|
output logic spi_clk_oe_o,
|
||||||
|
// SS
|
||||||
|
output logic spi_ss_o,
|
||||||
|
output logic spi_ss_oe_o,
|
||||||
|
// MOSI(DQ0)
|
||||||
|
input logic spi_dq0_i,
|
||||||
|
output logic spi_dq0_o,
|
||||||
|
output logic spi_dq0_oe_o,
|
||||||
|
// MISO(DQ1)
|
||||||
|
input logic spi_dq1_i,
|
||||||
|
output logic spi_dq1_o,
|
||||||
|
output logic spi_dq1_oe_o,
|
||||||
|
// DQ2
|
||||||
|
input logic spi_dq2_i,
|
||||||
|
output logic spi_dq2_o,
|
||||||
|
output logic spi_dq2_oe_o,
|
||||||
|
// DQ3
|
||||||
|
input logic spi_dq3_i,
|
||||||
|
output logic spi_dq3_o,
|
||||||
|
output logic spi_dq3_oe_o
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam S_IDLE = 4'b0001;
|
||||||
|
localparam S_SS_ACTIVE = 4'b0010;
|
||||||
|
localparam S_TRANSMIT = 4'b0100;
|
||||||
|
localparam S_SS_INACTIVE = 4'b1000;
|
||||||
|
|
||||||
|
logic data_valid;
|
||||||
|
logic [7:0] in_data;
|
||||||
|
|
||||||
|
logic [3:0] state_d, state_q;
|
||||||
|
logic [3:0] ss_delay_cnt_d, ss_delay_cnt_q;
|
||||||
|
logic [7:0] out_data_d, out_data_q;
|
||||||
|
logic start_d, start_q;
|
||||||
|
logic ready_d, ready_q;
|
||||||
|
|
||||||
|
logic spi_ss_d, spi_ss_q;
|
||||||
|
logic spi_ss_oe_d, spi_ss_oe_q;
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
state_d = state_q;
|
||||||
|
ss_delay_cnt_d = ss_delay_cnt_q;
|
||||||
|
out_data_d = out_data_q;
|
||||||
|
start_d = 1'b0;
|
||||||
|
ready_d = ready_q;
|
||||||
|
spi_ss_d = spi_ss_q;
|
||||||
|
spi_ss_oe_d = spi_ss_oe_q;
|
||||||
|
|
||||||
|
case (state_q)
|
||||||
|
S_IDLE: begin
|
||||||
|
spi_ss_oe_d = 1'b1;
|
||||||
|
spi_ss_d = 1'b1;
|
||||||
|
ready_d = 1'b1;
|
||||||
|
if (start_i) begin
|
||||||
|
out_data_d = data_i;
|
||||||
|
state_d = S_SS_ACTIVE;
|
||||||
|
ss_delay_cnt_d = '0;
|
||||||
|
ready_d = 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_SS_ACTIVE: begin
|
||||||
|
spi_ss_d = 1'b0;
|
||||||
|
ss_delay_cnt_d = ss_delay_cnt_q + 1'b1;
|
||||||
|
if (ss_delay_cnt_q == ss_delay_cnt_i) begin
|
||||||
|
state_d = S_TRANSMIT;
|
||||||
|
start_d = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_TRANSMIT: begin
|
||||||
|
// 还有数据要传输
|
||||||
|
if (data_valid && start_i) begin
|
||||||
|
out_data_d = data_i;
|
||||||
|
start_d = 1'b1;
|
||||||
|
// 没有数据要传输
|
||||||
|
end else if (data_valid && (!start_i)) begin
|
||||||
|
state_d = S_SS_INACTIVE;
|
||||||
|
ss_delay_cnt_d = '0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_SS_INACTIVE: begin
|
||||||
|
ss_delay_cnt_d = ss_delay_cnt_q + 1'b1;
|
||||||
|
if (ss_delay_cnt_q == ss_delay_cnt_i) begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
if (!rst_ni) begin
|
||||||
|
state_q <= S_IDLE;
|
||||||
|
ss_delay_cnt_q <= '0;
|
||||||
|
out_data_q <= '0;
|
||||||
|
start_q <= '0;
|
||||||
|
ready_q <= '0;
|
||||||
|
end else begin
|
||||||
|
state_q <= state_d;
|
||||||
|
ss_delay_cnt_q <= ss_delay_cnt_d;
|
||||||
|
out_data_q <= out_data_d;
|
||||||
|
start_q <= start_d;
|
||||||
|
ready_q <= ready_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
if (!rst_ni) begin
|
||||||
|
spi_ss_q <= '0;
|
||||||
|
spi_ss_oe_q <= '0;
|
||||||
|
end else begin
|
||||||
|
spi_ss_q <= spi_ss_d;
|
||||||
|
spi_ss_oe_q <= spi_ss_oe_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign data_valid_o = data_valid;
|
||||||
|
assign data_o = in_data;
|
||||||
|
assign ready_o = ready_q;
|
||||||
|
|
||||||
|
assign spi_ss_o = ss_sw_ctrl_i ? ss_level_i : spi_ss_q;
|
||||||
|
assign spi_ss_oe_o = spi_ss_oe_q;
|
||||||
|
|
||||||
|
spi_transmit_byte master_transmit_byte (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
.start_i (start_q),
|
||||||
|
.slave_mode_i(1'b0),
|
||||||
|
.read_i (read_i),
|
||||||
|
.spi_mode_i (spi_mode_i),
|
||||||
|
.cp_mode_i (cp_mode_i),
|
||||||
|
.data_i (out_data_q),
|
||||||
|
.div_ratio_i(div_ratio_i),
|
||||||
|
.msb_first_i(msb_first_i),
|
||||||
|
.data_o (in_data),
|
||||||
|
.ready_o (),
|
||||||
|
.data_valid_o(data_valid),
|
||||||
|
.spi_clk_i (),
|
||||||
|
.spi_clk_o (spi_clk_o),
|
||||||
|
.spi_clk_oe_o(spi_clk_oe_o),
|
||||||
|
.spi_ss_i (),
|
||||||
|
.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)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,210 @@
|
||||||
|
// Copyright lowRISC contributors.
|
||||||
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Register Package auto-generated by `reggen` containing data structure
|
||||||
|
|
||||||
|
package spi_reg_pkg;
|
||||||
|
|
||||||
|
// Address widths within the block
|
||||||
|
parameter int BlockAw = 4;
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
// Typedefs for registers //
|
||||||
|
////////////////////////////
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
struct packed {
|
||||||
|
logic q;
|
||||||
|
logic qe;
|
||||||
|
} enable;
|
||||||
|
struct packed {
|
||||||
|
logic q;
|
||||||
|
logic qe;
|
||||||
|
} int_en;
|
||||||
|
struct packed {
|
||||||
|
logic q;
|
||||||
|
logic qe;
|
||||||
|
} int_pending;
|
||||||
|
struct packed {
|
||||||
|
logic q;
|
||||||
|
logic qe;
|
||||||
|
} role_mode;
|
||||||
|
struct packed {
|
||||||
|
logic [1:0] q;
|
||||||
|
logic qe;
|
||||||
|
} cp_mode;
|
||||||
|
struct packed {
|
||||||
|
logic [1:0] q;
|
||||||
|
logic qe;
|
||||||
|
} spi_mode;
|
||||||
|
struct packed {
|
||||||
|
logic q;
|
||||||
|
logic qe;
|
||||||
|
} read;
|
||||||
|
struct packed {
|
||||||
|
logic q;
|
||||||
|
logic qe;
|
||||||
|
} msb_first;
|
||||||
|
struct packed {
|
||||||
|
logic q;
|
||||||
|
logic qe;
|
||||||
|
} ss_sw_ctrl;
|
||||||
|
struct packed {
|
||||||
|
logic q;
|
||||||
|
logic qe;
|
||||||
|
} ss_level;
|
||||||
|
struct packed {
|
||||||
|
logic [3:0] q;
|
||||||
|
logic qe;
|
||||||
|
} ss_delay;
|
||||||
|
struct packed {
|
||||||
|
logic [2:0] q;
|
||||||
|
logic qe;
|
||||||
|
} clk_div;
|
||||||
|
} spi_reg2hw_ctrl0_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
struct packed {
|
||||||
|
logic q;
|
||||||
|
} tx_fifo_full;
|
||||||
|
struct packed {
|
||||||
|
logic q;
|
||||||
|
} tx_fifo_empty;
|
||||||
|
struct packed {
|
||||||
|
logic q;
|
||||||
|
} rx_fifo_full;
|
||||||
|
struct packed {
|
||||||
|
logic q;
|
||||||
|
} rx_fifo_empty;
|
||||||
|
struct packed {
|
||||||
|
logic q;
|
||||||
|
} busy;
|
||||||
|
} spi_reg2hw_status_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
logic [7:0] q;
|
||||||
|
logic qe;
|
||||||
|
} spi_reg2hw_txdata_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
logic [7:0] q;
|
||||||
|
logic re;
|
||||||
|
} spi_reg2hw_rxdata_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
struct packed {
|
||||||
|
logic d;
|
||||||
|
logic de;
|
||||||
|
} enable;
|
||||||
|
struct packed {
|
||||||
|
logic d;
|
||||||
|
logic de;
|
||||||
|
} int_en;
|
||||||
|
struct packed {
|
||||||
|
logic d;
|
||||||
|
logic de;
|
||||||
|
} int_pending;
|
||||||
|
struct packed {
|
||||||
|
logic d;
|
||||||
|
logic de;
|
||||||
|
} role_mode;
|
||||||
|
struct packed {
|
||||||
|
logic [1:0] d;
|
||||||
|
logic de;
|
||||||
|
} cp_mode;
|
||||||
|
struct packed {
|
||||||
|
logic [1:0] d;
|
||||||
|
logic de;
|
||||||
|
} spi_mode;
|
||||||
|
struct packed {
|
||||||
|
logic d;
|
||||||
|
logic de;
|
||||||
|
} read;
|
||||||
|
struct packed {
|
||||||
|
logic d;
|
||||||
|
logic de;
|
||||||
|
} msb_first;
|
||||||
|
struct packed {
|
||||||
|
logic d;
|
||||||
|
logic de;
|
||||||
|
} ss_sw_ctrl;
|
||||||
|
struct packed {
|
||||||
|
logic d;
|
||||||
|
logic de;
|
||||||
|
} ss_level;
|
||||||
|
struct packed {
|
||||||
|
logic [3:0] d;
|
||||||
|
logic de;
|
||||||
|
} ss_delay;
|
||||||
|
struct packed {
|
||||||
|
logic [2:0] d;
|
||||||
|
logic de;
|
||||||
|
} clk_div;
|
||||||
|
} spi_hw2reg_ctrl0_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
struct packed {
|
||||||
|
logic d;
|
||||||
|
} tx_fifo_full;
|
||||||
|
struct packed {
|
||||||
|
logic d;
|
||||||
|
} tx_fifo_empty;
|
||||||
|
struct packed {
|
||||||
|
logic d;
|
||||||
|
} rx_fifo_full;
|
||||||
|
struct packed {
|
||||||
|
logic d;
|
||||||
|
} rx_fifo_empty;
|
||||||
|
struct packed {
|
||||||
|
logic d;
|
||||||
|
} busy;
|
||||||
|
} spi_hw2reg_status_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
logic [7:0] d;
|
||||||
|
} spi_hw2reg_rxdata_reg_t;
|
||||||
|
|
||||||
|
// Register -> HW type
|
||||||
|
typedef struct packed {
|
||||||
|
spi_reg2hw_ctrl0_reg_t ctrl0; // [53:23]
|
||||||
|
spi_reg2hw_status_reg_t status; // [22:18]
|
||||||
|
spi_reg2hw_txdata_reg_t txdata; // [17:9]
|
||||||
|
spi_reg2hw_rxdata_reg_t rxdata; // [8:0]
|
||||||
|
} spi_reg2hw_t;
|
||||||
|
|
||||||
|
// HW -> register type
|
||||||
|
typedef struct packed {
|
||||||
|
spi_hw2reg_ctrl0_reg_t ctrl0; // [43:13]
|
||||||
|
spi_hw2reg_status_reg_t status; // [12:8]
|
||||||
|
spi_hw2reg_rxdata_reg_t rxdata; // [7:0]
|
||||||
|
} spi_hw2reg_t;
|
||||||
|
|
||||||
|
// Register offsets
|
||||||
|
parameter logic [BlockAw-1:0] SPI_CTRL0_OFFSET = 4'h0;
|
||||||
|
parameter logic [BlockAw-1:0] SPI_STATUS_OFFSET = 4'h4;
|
||||||
|
parameter logic [BlockAw-1:0] SPI_TXDATA_OFFSET = 4'h8;
|
||||||
|
parameter logic [BlockAw-1:0] SPI_RXDATA_OFFSET = 4'hc;
|
||||||
|
|
||||||
|
// Reset values for hwext registers and their fields
|
||||||
|
parameter logic [4:0] SPI_STATUS_RESVAL = 5'h0;
|
||||||
|
parameter logic [7:0] SPI_RXDATA_RESVAL = 8'h0;
|
||||||
|
|
||||||
|
// Register index
|
||||||
|
typedef enum int {
|
||||||
|
SPI_CTRL0,
|
||||||
|
SPI_STATUS,
|
||||||
|
SPI_TXDATA,
|
||||||
|
SPI_RXDATA
|
||||||
|
} spi_id_e;
|
||||||
|
|
||||||
|
// Register width information to check illegal writes
|
||||||
|
parameter logic [3:0] SPI_PERMIT [4] = '{
|
||||||
|
4'b1111, // index[0] SPI_CTRL0
|
||||||
|
4'b0001, // index[1] SPI_STATUS
|
||||||
|
4'b0001, // index[2] SPI_TXDATA
|
||||||
|
4'b0001 // index[3] SPI_RXDATA
|
||||||
|
};
|
||||||
|
|
||||||
|
endpackage
|
||||||
|
|
|
@ -0,0 +1,613 @@
|
||||||
|
// Copyright lowRISC contributors.
|
||||||
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Register Top module auto-generated by `reggen`
|
||||||
|
|
||||||
|
|
||||||
|
module spi_reg_top (
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_ni,
|
||||||
|
|
||||||
|
// To HW
|
||||||
|
output spi_reg_pkg::spi_reg2hw_t reg2hw, // Write
|
||||||
|
input spi_reg_pkg::spi_hw2reg_t hw2reg, // Read
|
||||||
|
|
||||||
|
input logic reg_we,
|
||||||
|
input logic reg_re,
|
||||||
|
input logic [31:0] reg_wdata,
|
||||||
|
input logic [ 3:0] reg_be,
|
||||||
|
input logic [31:0] reg_addr,
|
||||||
|
output logic [31:0] reg_rdata
|
||||||
|
);
|
||||||
|
|
||||||
|
import spi_reg_pkg::* ;
|
||||||
|
|
||||||
|
localparam int AW = 4;
|
||||||
|
localparam int DW = 32;
|
||||||
|
localparam int DBW = DW/8; // Byte Width
|
||||||
|
|
||||||
|
logic reg_error;
|
||||||
|
logic addrmiss, wr_err;
|
||||||
|
|
||||||
|
logic [DW-1:0] reg_rdata_next;
|
||||||
|
|
||||||
|
assign reg_rdata = reg_rdata_next;
|
||||||
|
assign reg_error = wr_err;
|
||||||
|
|
||||||
|
// Define SW related signals
|
||||||
|
// Format: <reg>_<field>_{wd|we|qs}
|
||||||
|
// or <reg>_{wd|we|qs} if field == 1 or 0
|
||||||
|
logic ctrl0_we;
|
||||||
|
logic ctrl0_enable_qs;
|
||||||
|
logic ctrl0_enable_wd;
|
||||||
|
logic ctrl0_int_en_qs;
|
||||||
|
logic ctrl0_int_en_wd;
|
||||||
|
logic ctrl0_int_pending_qs;
|
||||||
|
logic ctrl0_int_pending_wd;
|
||||||
|
logic ctrl0_role_mode_qs;
|
||||||
|
logic ctrl0_role_mode_wd;
|
||||||
|
logic [1:0] ctrl0_cp_mode_qs;
|
||||||
|
logic [1:0] ctrl0_cp_mode_wd;
|
||||||
|
logic [1:0] ctrl0_spi_mode_qs;
|
||||||
|
logic [1:0] ctrl0_spi_mode_wd;
|
||||||
|
logic ctrl0_read_qs;
|
||||||
|
logic ctrl0_read_wd;
|
||||||
|
logic ctrl0_msb_first_qs;
|
||||||
|
logic ctrl0_msb_first_wd;
|
||||||
|
logic ctrl0_ss_sw_ctrl_qs;
|
||||||
|
logic ctrl0_ss_sw_ctrl_wd;
|
||||||
|
logic ctrl0_ss_level_qs;
|
||||||
|
logic ctrl0_ss_level_wd;
|
||||||
|
logic [3:0] ctrl0_ss_delay_qs;
|
||||||
|
logic [3:0] ctrl0_ss_delay_wd;
|
||||||
|
logic [2:0] ctrl0_clk_div_qs;
|
||||||
|
logic [2:0] ctrl0_clk_div_wd;
|
||||||
|
logic status_re;
|
||||||
|
logic status_tx_fifo_full_qs;
|
||||||
|
logic status_tx_fifo_empty_qs;
|
||||||
|
logic status_rx_fifo_full_qs;
|
||||||
|
logic status_rx_fifo_empty_qs;
|
||||||
|
logic status_busy_qs;
|
||||||
|
logic txdata_we;
|
||||||
|
logic [7:0] txdata_wd;
|
||||||
|
logic rxdata_re;
|
||||||
|
logic [7:0] rxdata_qs;
|
||||||
|
|
||||||
|
// Register instances
|
||||||
|
// R[ctrl0]: V(False)
|
||||||
|
|
||||||
|
// F[enable]: 0:0
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (1),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (1'h0)
|
||||||
|
) u_ctrl0_enable (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (ctrl0_we),
|
||||||
|
.wd (ctrl0_enable_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl0.enable.de),
|
||||||
|
.d (hw2reg.ctrl0.enable.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl0.enable.qe),
|
||||||
|
.q (reg2hw.ctrl0.enable.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl0_enable_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[int_en]: 1:1
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (1),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (1'h0)
|
||||||
|
) u_ctrl0_int_en (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (ctrl0_we),
|
||||||
|
.wd (ctrl0_int_en_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl0.int_en.de),
|
||||||
|
.d (hw2reg.ctrl0.int_en.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl0.int_en.qe),
|
||||||
|
.q (reg2hw.ctrl0.int_en.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl0_int_en_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[int_pending]: 2:2
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (1),
|
||||||
|
.SWACCESS("W1C"),
|
||||||
|
.RESVAL (1'h0)
|
||||||
|
) u_ctrl0_int_pending (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (ctrl0_we),
|
||||||
|
.wd (ctrl0_int_pending_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl0.int_pending.de),
|
||||||
|
.d (hw2reg.ctrl0.int_pending.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl0.int_pending.qe),
|
||||||
|
.q (reg2hw.ctrl0.int_pending.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl0_int_pending_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[role_mode]: 3:3
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (1),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (1'h0)
|
||||||
|
) u_ctrl0_role_mode (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (ctrl0_we),
|
||||||
|
.wd (ctrl0_role_mode_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl0.role_mode.de),
|
||||||
|
.d (hw2reg.ctrl0.role_mode.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl0.role_mode.qe),
|
||||||
|
.q (reg2hw.ctrl0.role_mode.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl0_role_mode_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[cp_mode]: 5:4
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (2),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (2'h0)
|
||||||
|
) u_ctrl0_cp_mode (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (ctrl0_we),
|
||||||
|
.wd (ctrl0_cp_mode_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl0.cp_mode.de),
|
||||||
|
.d (hw2reg.ctrl0.cp_mode.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl0.cp_mode.qe),
|
||||||
|
.q (reg2hw.ctrl0.cp_mode.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl0_cp_mode_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[spi_mode]: 7:6
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (2),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (2'h0)
|
||||||
|
) u_ctrl0_spi_mode (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (ctrl0_we),
|
||||||
|
.wd (ctrl0_spi_mode_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl0.spi_mode.de),
|
||||||
|
.d (hw2reg.ctrl0.spi_mode.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl0.spi_mode.qe),
|
||||||
|
.q (reg2hw.ctrl0.spi_mode.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl0_spi_mode_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[read]: 8:8
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (1),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (1'h0)
|
||||||
|
) u_ctrl0_read (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (ctrl0_we),
|
||||||
|
.wd (ctrl0_read_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl0.read.de),
|
||||||
|
.d (hw2reg.ctrl0.read.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl0.read.qe),
|
||||||
|
.q (reg2hw.ctrl0.read.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl0_read_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[msb_first]: 9:9
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (1),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (1'h0)
|
||||||
|
) u_ctrl0_msb_first (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (ctrl0_we),
|
||||||
|
.wd (ctrl0_msb_first_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl0.msb_first.de),
|
||||||
|
.d (hw2reg.ctrl0.msb_first.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl0.msb_first.qe),
|
||||||
|
.q (reg2hw.ctrl0.msb_first.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl0_msb_first_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[ss_sw_ctrl]: 10:10
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (1),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (1'h0)
|
||||||
|
) u_ctrl0_ss_sw_ctrl (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (ctrl0_we),
|
||||||
|
.wd (ctrl0_ss_sw_ctrl_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl0.ss_sw_ctrl.de),
|
||||||
|
.d (hw2reg.ctrl0.ss_sw_ctrl.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl0.ss_sw_ctrl.qe),
|
||||||
|
.q (reg2hw.ctrl0.ss_sw_ctrl.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl0_ss_sw_ctrl_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[ss_level]: 11:11
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (1),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (1'h0)
|
||||||
|
) u_ctrl0_ss_level (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (ctrl0_we),
|
||||||
|
.wd (ctrl0_ss_level_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl0.ss_level.de),
|
||||||
|
.d (hw2reg.ctrl0.ss_level.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl0.ss_level.qe),
|
||||||
|
.q (reg2hw.ctrl0.ss_level.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl0_ss_level_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[ss_delay]: 15:12
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (4),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (4'h0)
|
||||||
|
) u_ctrl0_ss_delay (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (ctrl0_we),
|
||||||
|
.wd (ctrl0_ss_delay_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl0.ss_delay.de),
|
||||||
|
.d (hw2reg.ctrl0.ss_delay.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl0.ss_delay.qe),
|
||||||
|
.q (reg2hw.ctrl0.ss_delay.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl0_ss_delay_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[clk_div]: 31:29
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (3),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (3'h0)
|
||||||
|
) u_ctrl0_clk_div (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (ctrl0_we),
|
||||||
|
.wd (ctrl0_clk_div_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.ctrl0.clk_div.de),
|
||||||
|
.d (hw2reg.ctrl0.clk_div.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.ctrl0.clk_div.qe),
|
||||||
|
.q (reg2hw.ctrl0.clk_div.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (ctrl0_clk_div_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// R[status]: V(True)
|
||||||
|
|
||||||
|
// F[tx_fifo_full]: 0:0
|
||||||
|
prim_subreg_ext #(
|
||||||
|
.DW (1)
|
||||||
|
) u_status_tx_fifo_full (
|
||||||
|
.re (status_re),
|
||||||
|
.we (1'b0),
|
||||||
|
.wd ('0),
|
||||||
|
.d (hw2reg.status.tx_fifo_full.d),
|
||||||
|
.qre (),
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.status.tx_fifo_full.q),
|
||||||
|
.qs (status_tx_fifo_full_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[tx_fifo_empty]: 1:1
|
||||||
|
prim_subreg_ext #(
|
||||||
|
.DW (1)
|
||||||
|
) u_status_tx_fifo_empty (
|
||||||
|
.re (status_re),
|
||||||
|
.we (1'b0),
|
||||||
|
.wd ('0),
|
||||||
|
.d (hw2reg.status.tx_fifo_empty.d),
|
||||||
|
.qre (),
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.status.tx_fifo_empty.q),
|
||||||
|
.qs (status_tx_fifo_empty_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[rx_fifo_full]: 2:2
|
||||||
|
prim_subreg_ext #(
|
||||||
|
.DW (1)
|
||||||
|
) u_status_rx_fifo_full (
|
||||||
|
.re (status_re),
|
||||||
|
.we (1'b0),
|
||||||
|
.wd ('0),
|
||||||
|
.d (hw2reg.status.rx_fifo_full.d),
|
||||||
|
.qre (),
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.status.rx_fifo_full.q),
|
||||||
|
.qs (status_rx_fifo_full_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[rx_fifo_empty]: 3:3
|
||||||
|
prim_subreg_ext #(
|
||||||
|
.DW (1)
|
||||||
|
) u_status_rx_fifo_empty (
|
||||||
|
.re (status_re),
|
||||||
|
.we (1'b0),
|
||||||
|
.wd ('0),
|
||||||
|
.d (hw2reg.status.rx_fifo_empty.d),
|
||||||
|
.qre (),
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.status.rx_fifo_empty.q),
|
||||||
|
.qs (status_rx_fifo_empty_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// F[busy]: 4:4
|
||||||
|
prim_subreg_ext #(
|
||||||
|
.DW (1)
|
||||||
|
) u_status_busy (
|
||||||
|
.re (status_re),
|
||||||
|
.we (1'b0),
|
||||||
|
.wd ('0),
|
||||||
|
.d (hw2reg.status.busy.d),
|
||||||
|
.qre (),
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.status.busy.q),
|
||||||
|
.qs (status_busy_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// R[txdata]: V(False)
|
||||||
|
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (8),
|
||||||
|
.SWACCESS("WO"),
|
||||||
|
.RESVAL (8'h0)
|
||||||
|
) u_txdata (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (txdata_we),
|
||||||
|
.wd (txdata_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (1'b0),
|
||||||
|
.d ('0),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (reg2hw.txdata.qe),
|
||||||
|
.q (reg2hw.txdata.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs ()
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// R[rxdata]: V(True)
|
||||||
|
|
||||||
|
prim_subreg_ext #(
|
||||||
|
.DW (8)
|
||||||
|
) u_rxdata (
|
||||||
|
.re (rxdata_re),
|
||||||
|
.we (1'b0),
|
||||||
|
.wd ('0),
|
||||||
|
.d (hw2reg.rxdata.d),
|
||||||
|
.qre (reg2hw.rxdata.re),
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.rxdata.q),
|
||||||
|
.qs (rxdata_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
logic [3:0] addr_hit;
|
||||||
|
always_comb begin
|
||||||
|
addr_hit = '0;
|
||||||
|
addr_hit[0] = (reg_addr == SPI_CTRL0_OFFSET);
|
||||||
|
addr_hit[1] = (reg_addr == SPI_STATUS_OFFSET);
|
||||||
|
addr_hit[2] = (reg_addr == SPI_TXDATA_OFFSET);
|
||||||
|
addr_hit[3] = (reg_addr == SPI_RXDATA_OFFSET);
|
||||||
|
end
|
||||||
|
|
||||||
|
assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
|
||||||
|
|
||||||
|
// Check sub-word write is permitted
|
||||||
|
always_comb begin
|
||||||
|
wr_err = (reg_we &
|
||||||
|
((addr_hit[0] & (|(SPI_PERMIT[0] & ~reg_be))) |
|
||||||
|
(addr_hit[1] & (|(SPI_PERMIT[1] & ~reg_be))) |
|
||||||
|
(addr_hit[2] & (|(SPI_PERMIT[2] & ~reg_be))) |
|
||||||
|
(addr_hit[3] & (|(SPI_PERMIT[3] & ~reg_be)))));
|
||||||
|
end
|
||||||
|
|
||||||
|
assign ctrl0_we = addr_hit[0] & reg_we & !reg_error;
|
||||||
|
|
||||||
|
assign ctrl0_enable_wd = reg_wdata[0];
|
||||||
|
|
||||||
|
assign ctrl0_int_en_wd = reg_wdata[1];
|
||||||
|
|
||||||
|
assign ctrl0_int_pending_wd = reg_wdata[2];
|
||||||
|
|
||||||
|
assign ctrl0_role_mode_wd = reg_wdata[3];
|
||||||
|
|
||||||
|
assign ctrl0_cp_mode_wd = reg_wdata[5:4];
|
||||||
|
|
||||||
|
assign ctrl0_spi_mode_wd = reg_wdata[7:6];
|
||||||
|
|
||||||
|
assign ctrl0_read_wd = reg_wdata[8];
|
||||||
|
|
||||||
|
assign ctrl0_msb_first_wd = reg_wdata[9];
|
||||||
|
|
||||||
|
assign ctrl0_ss_sw_ctrl_wd = reg_wdata[10];
|
||||||
|
|
||||||
|
assign ctrl0_ss_level_wd = reg_wdata[11];
|
||||||
|
|
||||||
|
assign ctrl0_ss_delay_wd = reg_wdata[15:12];
|
||||||
|
|
||||||
|
assign ctrl0_clk_div_wd = reg_wdata[31:29];
|
||||||
|
assign status_re = addr_hit[1] & reg_re & !reg_error;
|
||||||
|
assign txdata_we = addr_hit[2] & reg_we & !reg_error;
|
||||||
|
|
||||||
|
assign txdata_wd = reg_wdata[7:0];
|
||||||
|
assign rxdata_re = addr_hit[3] & reg_re & !reg_error;
|
||||||
|
|
||||||
|
// Read data return
|
||||||
|
always_comb begin
|
||||||
|
reg_rdata_next = '0;
|
||||||
|
unique case (1'b1)
|
||||||
|
addr_hit[0]: begin
|
||||||
|
reg_rdata_next[0] = ctrl0_enable_qs;
|
||||||
|
reg_rdata_next[1] = ctrl0_int_en_qs;
|
||||||
|
reg_rdata_next[2] = ctrl0_int_pending_qs;
|
||||||
|
reg_rdata_next[3] = ctrl0_role_mode_qs;
|
||||||
|
reg_rdata_next[5:4] = ctrl0_cp_mode_qs;
|
||||||
|
reg_rdata_next[7:6] = ctrl0_spi_mode_qs;
|
||||||
|
reg_rdata_next[8] = ctrl0_read_qs;
|
||||||
|
reg_rdata_next[9] = ctrl0_msb_first_qs;
|
||||||
|
reg_rdata_next[10] = ctrl0_ss_sw_ctrl_qs;
|
||||||
|
reg_rdata_next[11] = ctrl0_ss_level_qs;
|
||||||
|
reg_rdata_next[15:12] = ctrl0_ss_delay_qs;
|
||||||
|
reg_rdata_next[31:29] = ctrl0_clk_div_qs;
|
||||||
|
end
|
||||||
|
|
||||||
|
addr_hit[1]: begin
|
||||||
|
reg_rdata_next[0] = status_tx_fifo_full_qs;
|
||||||
|
reg_rdata_next[1] = status_tx_fifo_empty_qs;
|
||||||
|
reg_rdata_next[2] = status_rx_fifo_full_qs;
|
||||||
|
reg_rdata_next[3] = status_rx_fifo_empty_qs;
|
||||||
|
reg_rdata_next[4] = status_busy_qs;
|
||||||
|
end
|
||||||
|
|
||||||
|
addr_hit[2]: begin
|
||||||
|
reg_rdata_next[7:0] = '0;
|
||||||
|
end
|
||||||
|
|
||||||
|
addr_hit[3]: begin
|
||||||
|
reg_rdata_next[7:0] = rxdata_qs;
|
||||||
|
end
|
||||||
|
|
||||||
|
default: begin
|
||||||
|
reg_rdata_next = '1;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
// Unused signal tieoff
|
||||||
|
|
||||||
|
// wdata / byte enable are not always fully used
|
||||||
|
// add a blanket unused statement to handle lint waivers
|
||||||
|
logic unused_wdata;
|
||||||
|
logic unused_be;
|
||||||
|
assign unused_wdata = ^reg_wdata;
|
||||||
|
assign unused_be = ^reg_be;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
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_top (
|
||||||
|
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 req_i,
|
||||||
|
input logic we_i,
|
||||||
|
input logic [ 3:0] be_i,
|
||||||
|
input logic [31:0] addr_i,
|
||||||
|
input logic [31:0] data_i,
|
||||||
|
output logic gnt_o,
|
||||||
|
output logic rvalid_o,
|
||||||
|
output logic [31:0] data_o
|
||||||
|
);
|
||||||
|
|
||||||
|
logic re;
|
||||||
|
logic we;
|
||||||
|
logic [31:0] addr;
|
||||||
|
logic [31:0] reg_rdata;
|
||||||
|
|
||||||
|
assign gnt_o = req_i;
|
||||||
|
|
||||||
|
// 读信号
|
||||||
|
assign re = req_i & (!we_i);
|
||||||
|
// 写信号
|
||||||
|
assign we = req_i & we_i;
|
||||||
|
// 去掉基地址
|
||||||
|
assign addr = {16'h0, addr_i[15:0]};
|
||||||
|
|
||||||
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
if (!rst_ni) begin
|
||||||
|
rvalid_o <= '0;
|
||||||
|
data_o <= '0;
|
||||||
|
end else begin
|
||||||
|
rvalid_o <= req_i;
|
||||||
|
data_o <= reg_rdata;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
spi_core u_spi_core (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
.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),
|
||||||
|
.irq_o (irq_o),
|
||||||
|
.reg_we_i (we),
|
||||||
|
.reg_re_i (re),
|
||||||
|
.reg_wdata_i(data_i),
|
||||||
|
.reg_be_i (be_i),
|
||||||
|
.reg_addr_i (addr),
|
||||||
|
.reg_rdata_o(reg_rdata)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,332 @@
|
||||||
|
/*
|
||||||
|
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_transmit_byte (
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_ni,
|
||||||
|
|
||||||
|
input logic start_i, // 开始传输
|
||||||
|
input logic slave_mode_i, // 0: master, 1: slave.目前暂不支持slave模式!!!
|
||||||
|
input logic read_i, // 0: write, 1: read
|
||||||
|
input logic [1:0] spi_mode_i, // 0: SPI, 1: Dual SPI, 2: Quad SPI, 3: SPI
|
||||||
|
input logic [1:0] cp_mode_i, // [1]表示CPOL, [0]表示CPHA
|
||||||
|
input logic [7:0] data_i, // 字节输入
|
||||||
|
input logic [2:0] div_ratio_i, // 分频比
|
||||||
|
input logic msb_first_i, // 1: MSB, 0: LSB
|
||||||
|
output logic [7:0] data_o, // 接收到的数据输出
|
||||||
|
output logic ready_o, // 1: IDLE, 0: 正在传输
|
||||||
|
output logic data_valid_o, // 数据输出有效
|
||||||
|
|
||||||
|
// CLK
|
||||||
|
input logic spi_clk_i,
|
||||||
|
output logic spi_clk_o,
|
||||||
|
output logic spi_clk_oe_o,
|
||||||
|
// SS(slave模式使用)
|
||||||
|
input logic spi_ss_i,
|
||||||
|
// MOSI(DQ0)
|
||||||
|
input logic spi_dq0_i,
|
||||||
|
output logic spi_dq0_o,
|
||||||
|
output logic spi_dq0_oe_o,
|
||||||
|
// MISO(DQ1)
|
||||||
|
input logic spi_dq1_i,
|
||||||
|
output logic spi_dq1_o,
|
||||||
|
output logic spi_dq1_oe_o,
|
||||||
|
// DQ2
|
||||||
|
input logic spi_dq2_i,
|
||||||
|
output logic spi_dq2_o,
|
||||||
|
output logic spi_dq2_oe_o,
|
||||||
|
// DQ3
|
||||||
|
input logic spi_dq3_i,
|
||||||
|
output logic spi_dq3_o,
|
||||||
|
output logic spi_dq3_oe_o
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam MODE_STAND_SPI = 2'b00;
|
||||||
|
localparam MODE_DUAL_SPI = 2'b01;
|
||||||
|
localparam MODE_QUAD_SPI = 2'b10;
|
||||||
|
|
||||||
|
localparam S_IDLE = 3'b001;
|
||||||
|
localparam S_DATA = 3'b010;
|
||||||
|
localparam S_END = 3'b100;
|
||||||
|
|
||||||
|
logic tick;
|
||||||
|
|
||||||
|
logic [2:0] state_d, state_q;
|
||||||
|
logic [4:0] edge_cnt_d, edge_cnt_q;
|
||||||
|
logic [7:0] in_data_d, in_data_q;
|
||||||
|
logic [7:0] out_data_d, out_data_q;
|
||||||
|
logic [4:0] total_edge_cnt_d, total_edge_cnt_q;
|
||||||
|
logic data_valid_d, data_valid_q;
|
||||||
|
logic ready_d, ready_q;
|
||||||
|
|
||||||
|
logic spi_clk_d, spi_clk_q;
|
||||||
|
logic spi_clk_oe_d, spi_clk_oe_q;
|
||||||
|
logic spi_dq0_d, spi_dq0_q;
|
||||||
|
logic spi_dq0_oe_d, spi_dq0_oe_q;
|
||||||
|
logic spi_dq1_d, spi_dq1_q;
|
||||||
|
logic spi_dq1_oe_d, spi_dq1_oe_q;
|
||||||
|
logic spi_dq2_d, spi_dq2_q;
|
||||||
|
logic spi_dq2_oe_d, spi_dq2_oe_q;
|
||||||
|
logic spi_dq3_d, spi_dq3_q;
|
||||||
|
logic spi_dq3_oe_d, spi_dq3_oe_q;
|
||||||
|
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
state_d = state_q;
|
||||||
|
edge_cnt_d = edge_cnt_q;
|
||||||
|
in_data_d = in_data_q;
|
||||||
|
out_data_d = out_data_q;
|
||||||
|
data_valid_d = data_valid_q;
|
||||||
|
ready_d = ready_q;
|
||||||
|
|
||||||
|
spi_clk_d = spi_clk_q;
|
||||||
|
|
||||||
|
case (state_q)
|
||||||
|
S_IDLE: begin
|
||||||
|
spi_clk_d = cp_mode_i[1];
|
||||||
|
data_valid_d = 1'b0;
|
||||||
|
ready_d = 1'b1;
|
||||||
|
if (start_i) begin
|
||||||
|
edge_cnt_d = '0;
|
||||||
|
ready_d = 1'b0;
|
||||||
|
state_d = S_DATA;
|
||||||
|
if (msb_first_i) begin
|
||||||
|
out_data_d = data_i;
|
||||||
|
end else begin
|
||||||
|
out_data_d[7] = data_i[0];
|
||||||
|
out_data_d[6] = data_i[1];
|
||||||
|
out_data_d[5] = data_i[2];
|
||||||
|
out_data_d[4] = data_i[3];
|
||||||
|
out_data_d[3] = data_i[4];
|
||||||
|
out_data_d[2] = data_i[5];
|
||||||
|
out_data_d[1] = data_i[6];
|
||||||
|
out_data_d[0] = data_i[7];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_DATA: begin
|
||||||
|
if (tick) begin
|
||||||
|
spi_clk_d = ~spi_clk_q;
|
||||||
|
edge_cnt_d = edge_cnt_q + 1'b1;
|
||||||
|
// 第奇数个沿(1, 3, 5...)
|
||||||
|
if (!edge_cnt_q[0]) begin
|
||||||
|
// 出数据
|
||||||
|
if (cp_mode_i[0]) begin
|
||||||
|
// 第一个bit(s)在IDLE状态时已经送出了
|
||||||
|
if (edge_cnt_q != 5'd0) begin
|
||||||
|
case (spi_mode_i)
|
||||||
|
MODE_STAND_SPI: out_data_d = {out_data_q[6:0], 1'b0};
|
||||||
|
MODE_DUAL_SPI : out_data_d = {out_data_q[5:0], 2'b0};
|
||||||
|
MODE_QUAD_SPI : out_data_d = {out_data_q[3:0], 4'b0};
|
||||||
|
default: out_data_d = {out_data_q[6:0], 1'b0};
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
// 采数据
|
||||||
|
end else begin
|
||||||
|
case (spi_mode_i)
|
||||||
|
MODE_STAND_SPI: in_data_d = {in_data_q[6:0], spi_dq1_i};
|
||||||
|
MODE_DUAL_SPI : in_data_d = {in_data_q[5:0], spi_dq1_i, spi_dq0_i};
|
||||||
|
MODE_QUAD_SPI : in_data_d = {in_data_q[3:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
|
||||||
|
default : in_data_d = {in_data_q[6:0], spi_dq1_i};
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
// 第偶数个沿(2, 4, 6...)
|
||||||
|
end else begin
|
||||||
|
// 出数据
|
||||||
|
if (!cp_mode_i[0]) begin
|
||||||
|
case (spi_mode_i)
|
||||||
|
MODE_STAND_SPI: out_data_d = {out_data_q[6:0], 1'b0};
|
||||||
|
MODE_DUAL_SPI : out_data_d = {out_data_q[5:0], 2'b0};
|
||||||
|
MODE_QUAD_SPI : out_data_d = {out_data_q[3:0], 4'b0};
|
||||||
|
default: out_data_d = {out_data_q[6:0], 1'b0};
|
||||||
|
endcase
|
||||||
|
// 采数据
|
||||||
|
end else begin
|
||||||
|
case (spi_mode_i)
|
||||||
|
MODE_STAND_SPI: in_data_d = {in_data_q[6:0], spi_dq1_i};
|
||||||
|
MODE_DUAL_SPI : in_data_d = {in_data_q[5:0], spi_dq1_i, spi_dq0_i};
|
||||||
|
MODE_QUAD_SPI : in_data_d = {in_data_q[3:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
|
||||||
|
default : in_data_d = {in_data_q[6:0], spi_dq1_i};
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// 最后一个沿
|
||||||
|
if (edge_cnt_q == total_edge_cnt_q) begin
|
||||||
|
state_d = S_END;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_END: begin
|
||||||
|
if (tick) begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
data_valid_d = 1'b1;
|
||||||
|
if (!msb_first_i) begin
|
||||||
|
in_data_d[0] = in_data_q[7];
|
||||||
|
in_data_d[1] = in_data_q[6];
|
||||||
|
in_data_d[2] = in_data_q[5];
|
||||||
|
in_data_d[3] = in_data_q[4];
|
||||||
|
in_data_d[4] = in_data_q[3];
|
||||||
|
in_data_d[5] = in_data_q[2];
|
||||||
|
in_data_d[6] = in_data_q[1];
|
||||||
|
in_data_d[7] = in_data_q[0];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
total_edge_cnt_d = 5'd15;
|
||||||
|
|
||||||
|
case (spi_mode_i)
|
||||||
|
MODE_STAND_SPI: total_edge_cnt_d = 5'd15;
|
||||||
|
MODE_DUAL_SPI : total_edge_cnt_d = 5'd7;
|
||||||
|
MODE_QUAD_SPI : total_edge_cnt_d = 5'd3;
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
if (!rst_ni) begin
|
||||||
|
state_q <= S_IDLE;
|
||||||
|
edge_cnt_q <= '0;
|
||||||
|
total_edge_cnt_q <= '0;
|
||||||
|
in_data_q <= '0;
|
||||||
|
out_data_q <= '0;
|
||||||
|
data_valid_q <= '0;
|
||||||
|
ready_q <= '0;
|
||||||
|
end else begin
|
||||||
|
state_q <= state_d;
|
||||||
|
edge_cnt_q <= edge_cnt_d;
|
||||||
|
total_edge_cnt_q <= total_edge_cnt_d;
|
||||||
|
in_data_q <= in_data_d;
|
||||||
|
out_data_q <= out_data_d;
|
||||||
|
data_valid_q <= data_valid_d;
|
||||||
|
ready_q <= ready_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
spi_dq0_d = 1'b0;
|
||||||
|
spi_dq1_d = 1'b0;
|
||||||
|
spi_dq2_d = 1'b0;
|
||||||
|
spi_dq3_d = 1'b0;
|
||||||
|
spi_dq0_oe_d = 1'b0;
|
||||||
|
spi_dq1_oe_d = 1'b0;
|
||||||
|
spi_dq2_oe_d = 1'b0;
|
||||||
|
spi_dq3_oe_d = 1'b0;
|
||||||
|
|
||||||
|
case (spi_mode_i)
|
||||||
|
MODE_STAND_SPI: begin
|
||||||
|
spi_dq0_d = out_data_d[7];
|
||||||
|
spi_dq0_oe_d = 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
MODE_DUAL_SPI: begin
|
||||||
|
spi_dq0_d = out_data_d[6];
|
||||||
|
spi_dq1_d = out_data_d[7];
|
||||||
|
if (read_i) begin
|
||||||
|
spi_dq0_oe_d = 1'b0;
|
||||||
|
spi_dq1_oe_d = 1'b0;
|
||||||
|
end else begin
|
||||||
|
spi_dq0_oe_d = 1'b1;
|
||||||
|
spi_dq1_oe_d = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
MODE_QUAD_SPI: begin
|
||||||
|
spi_dq0_d = out_data_d[4];
|
||||||
|
spi_dq1_d = out_data_d[5];
|
||||||
|
spi_dq2_d = out_data_d[6];
|
||||||
|
spi_dq3_d = out_data_d[7];
|
||||||
|
if (read_i) begin
|
||||||
|
spi_dq0_oe_d = 1'b0;
|
||||||
|
spi_dq1_oe_d = 1'b0;
|
||||||
|
spi_dq2_oe_d = 1'b0;
|
||||||
|
spi_dq3_oe_d = 1'b0;
|
||||||
|
end else begin
|
||||||
|
spi_dq0_oe_d = 1'b1;
|
||||||
|
spi_dq1_oe_d = 1'b1;
|
||||||
|
spi_dq2_oe_d = 1'b1;
|
||||||
|
spi_dq3_oe_d = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
assign spi_clk_oe_d = slave_mode_i ? 1'b0 : 1'b1;
|
||||||
|
|
||||||
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
if (!rst_ni) begin
|
||||||
|
spi_clk_q <= '0;
|
||||||
|
spi_clk_oe_q <= '0;
|
||||||
|
spi_dq0_q <= '0;
|
||||||
|
spi_dq0_oe_q <= '0;
|
||||||
|
spi_dq1_q <= '0;
|
||||||
|
spi_dq1_oe_q <= '0;
|
||||||
|
spi_dq2_q <= '0;
|
||||||
|
spi_dq2_oe_q <= '0;
|
||||||
|
spi_dq3_q <= '0;
|
||||||
|
spi_dq3_oe_q <= '0;
|
||||||
|
end else begin
|
||||||
|
spi_clk_q <= spi_clk_d;
|
||||||
|
spi_clk_oe_q <= spi_clk_oe_d;
|
||||||
|
spi_dq0_q <= spi_dq0_d;
|
||||||
|
spi_dq0_oe_q <= spi_dq0_oe_d;
|
||||||
|
spi_dq1_q <= spi_dq1_d;
|
||||||
|
spi_dq1_oe_q <= spi_dq1_oe_d;
|
||||||
|
spi_dq2_q <= spi_dq2_d;
|
||||||
|
spi_dq2_oe_q <= spi_dq2_oe_d;
|
||||||
|
spi_dq3_q <= spi_dq3_d;
|
||||||
|
spi_dq3_oe_q <= spi_dq3_oe_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign data_o = in_data_q;
|
||||||
|
assign data_valid_o = data_valid_q;
|
||||||
|
assign ready_o = ready_q;
|
||||||
|
|
||||||
|
assign spi_clk_o = spi_clk_q;
|
||||||
|
assign spi_clk_oe_o = spi_clk_oe_q;
|
||||||
|
assign spi_dq0_o = spi_dq0_q;
|
||||||
|
assign spi_dq0_oe_o = spi_dq0_oe_q;
|
||||||
|
assign spi_dq1_o = spi_dq1_q;
|
||||||
|
assign spi_dq1_oe_o = spi_dq1_oe_q;
|
||||||
|
assign spi_dq2_o = spi_dq2_q;
|
||||||
|
assign spi_dq2_oe_o = spi_dq2_oe_q;
|
||||||
|
assign spi_dq3_o = spi_dq3_q;
|
||||||
|
assign spi_dq3_oe_o = spi_dq3_oe_q;
|
||||||
|
|
||||||
|
logic [15:0] ratio = 1 << div_ratio_i;
|
||||||
|
|
||||||
|
clk_div #(
|
||||||
|
.RATIO_WIDTH(16)
|
||||||
|
) u_clk_div (
|
||||||
|
.clk_i(clk_i),
|
||||||
|
.rst_ni(rst_ni || (~((state_q == S_IDLE) && start_i))),
|
||||||
|
.en_i(state_q != S_IDLE),
|
||||||
|
.ratio_i(ratio),
|
||||||
|
.clk_o(tick)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -34,6 +34,13 @@ module tinyriscv_soc_top #(
|
||||||
inout wire i2c_scl_pin, // I2C SCL引脚
|
inout wire i2c_scl_pin, // I2C SCL引脚
|
||||||
inout wire i2c_sda_pin, // I2C SDA引脚
|
inout wire i2c_sda_pin, // I2C SDA引脚
|
||||||
|
|
||||||
|
inout wire spi_clk_pin, // SPI CLK引脚
|
||||||
|
inout wire spi_ss_pin, // SPI SS引脚
|
||||||
|
inout wire spi_dq0_pin, // SPI DQ0(MOSI)引脚
|
||||||
|
inout wire spi_dq1_pin, // SPI DQ1(MISO)引脚
|
||||||
|
inout wire spi_dq2_pin, // SPI DQ2引脚
|
||||||
|
inout wire spi_dq3_pin, // SPI DQ3引脚
|
||||||
|
|
||||||
inout wire[1:0] gpio_pins, // GPIO引脚,1bit代表一个GPIO
|
inout wire[1:0] gpio_pins, // GPIO引脚,1bit代表一个GPIO
|
||||||
|
|
||||||
`ifdef VERILATOR
|
`ifdef VERILATOR
|
||||||
|
@ -49,9 +56,9 @@ module tinyriscv_soc_top #(
|
||||||
|
|
||||||
localparam int MASTERS = 3; // Number of master ports
|
localparam int MASTERS = 3; // Number of master ports
|
||||||
`ifdef VERILATOR
|
`ifdef VERILATOR
|
||||||
localparam int SLAVES = 9; // Number of slave ports
|
localparam int SLAVES = 10; // Number of slave ports
|
||||||
`else
|
`else
|
||||||
localparam int SLAVES = 8; // Number of slave ports
|
localparam int SLAVES = 9; // Number of slave ports
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
// masters
|
// masters
|
||||||
|
@ -68,8 +75,9 @@ module tinyriscv_soc_top #(
|
||||||
localparam int Uart0 = 5;
|
localparam int Uart0 = 5;
|
||||||
localparam int Rvic = 6;
|
localparam int Rvic = 6;
|
||||||
localparam int I2c0 = 7;
|
localparam int I2c0 = 7;
|
||||||
|
localparam int Spi0 = 8;
|
||||||
`ifdef VERILATOR
|
`ifdef VERILATOR
|
||||||
localparam int SimCtrl = 8;
|
localparam int SimCtrl = 9;
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,6 +127,7 @@ module tinyriscv_soc_top #(
|
||||||
wire gpio0_irq;
|
wire gpio0_irq;
|
||||||
wire gpio1_irq;
|
wire gpio1_irq;
|
||||||
wire i2c0_irq;
|
wire i2c0_irq;
|
||||||
|
wire spi0_irq;
|
||||||
|
|
||||||
wire[GPIO_NUM-1:0] gpio_data_in;
|
wire[GPIO_NUM-1:0] gpio_data_in;
|
||||||
wire[GPIO_NUM-1:0] gpio_oe;
|
wire[GPIO_NUM-1:0] gpio_oe;
|
||||||
|
@ -131,6 +140,25 @@ module tinyriscv_soc_top #(
|
||||||
wire i2c_sda_oe;
|
wire i2c_sda_oe;
|
||||||
wire i2c_sda_out;
|
wire i2c_sda_out;
|
||||||
|
|
||||||
|
wire spi_clk_in;
|
||||||
|
wire spi_clk_oe;
|
||||||
|
wire spi_clk_out;
|
||||||
|
wire spi_ss_in;
|
||||||
|
wire spi_ss_oe;
|
||||||
|
wire spi_ss_out;
|
||||||
|
wire spi_dq0_in;
|
||||||
|
wire spi_dq0_oe;
|
||||||
|
wire spi_dq0_out;
|
||||||
|
wire spi_dq1_in;
|
||||||
|
wire spi_dq1_oe;
|
||||||
|
wire spi_dq1_out;
|
||||||
|
wire spi_dq2_in;
|
||||||
|
wire spi_dq2_oe;
|
||||||
|
wire spi_dq2_out;
|
||||||
|
wire spi_dq3_in;
|
||||||
|
wire spi_dq3_oe;
|
||||||
|
wire spi_dq3_out;
|
||||||
|
|
||||||
always @ (*) begin
|
always @ (*) begin
|
||||||
irq_src = 32'h0;
|
irq_src = 32'h0;
|
||||||
irq_src[0] = timer0_irq;
|
irq_src[0] = timer0_irq;
|
||||||
|
@ -138,6 +166,7 @@ module tinyriscv_soc_top #(
|
||||||
irq_src[2] = gpio0_irq;
|
irq_src[2] = gpio0_irq;
|
||||||
irq_src[3] = gpio1_irq;
|
irq_src[3] = gpio1_irq;
|
||||||
irq_src[4] = i2c0_irq;
|
irq_src[4] = i2c0_irq;
|
||||||
|
irq_src[5] = spi0_irq;
|
||||||
end
|
end
|
||||||
|
|
||||||
`ifdef VERILATOR
|
`ifdef VERILATOR
|
||||||
|
@ -328,10 +357,58 @@ module tinyriscv_soc_top #(
|
||||||
.data_o (slave_rdata[I2c0])
|
.data_o (slave_rdata[I2c0])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assign spi_clk_pin = spi_clk_oe ? spi_clk_out : 1'bz;
|
||||||
|
assign spi_clk_in = spi_clk_pin;
|
||||||
|
assign spi_ss_pin = spi_ss_oe ? spi_ss_out : 1'bz;
|
||||||
|
assign spi_ss_in = spi_ss_pin;
|
||||||
|
assign spi_dq0_pin = spi_dq0_oe ? spi_dq0_out : 1'bz;
|
||||||
|
assign spi_dq0_in = spi_dq0_pin;
|
||||||
|
assign spi_dq1_pin = spi_dq1_oe ? spi_dq1_out : 1'bz;
|
||||||
|
assign spi_dq1_in = spi_dq1_pin;
|
||||||
|
assign spi_dq2_pin = spi_dq2_oe ? spi_dq2_out : 1'bz;
|
||||||
|
assign spi_dq2_in = spi_dq2_pin;
|
||||||
|
assign spi_dq3_pin = spi_dq3_oe ? spi_dq3_out : 1'bz;
|
||||||
|
assign spi_dq3_in = spi_dq3_pin;
|
||||||
|
|
||||||
|
assign slave_addr_mask[Spi0] = `SPI0_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Spi0] = `SPI0_ADDR_BASE;
|
||||||
|
// 8.SPI0模块
|
||||||
|
spi_top spi0(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.spi_clk_i (spi_clk_in),
|
||||||
|
.spi_clk_o (spi_clk_out),
|
||||||
|
.spi_clk_oe_o(spi_clk_oe),
|
||||||
|
.spi_ss_i (spi_ss_in),
|
||||||
|
.spi_ss_o (spi_ss_out),
|
||||||
|
.spi_ss_oe_o(spi_ss_oe),
|
||||||
|
.spi_dq0_i (spi_dq0_in),
|
||||||
|
.spi_dq0_o (spi_dq0_out),
|
||||||
|
.spi_dq0_oe_o(spi_dq0_oe),
|
||||||
|
.spi_dq1_i (spi_dq1_in),
|
||||||
|
.spi_dq1_o (spi_dq1_out),
|
||||||
|
.spi_dq1_oe_o(spi_dq1_oe),
|
||||||
|
.spi_dq2_i (spi_dq2_in),
|
||||||
|
.spi_dq2_o (spi_dq2_out),
|
||||||
|
.spi_dq2_oe_o(spi_dq2_oe),
|
||||||
|
.spi_dq3_i (spi_dq3_in),
|
||||||
|
.spi_dq3_o (spi_dq3_out),
|
||||||
|
.spi_dq3_oe_o(spi_dq3_oe),
|
||||||
|
.irq_o (spi0_irq),
|
||||||
|
.req_i (slave_req[Spi0]),
|
||||||
|
.we_i (slave_we[Spi0]),
|
||||||
|
.be_i (slave_be[Spi0]),
|
||||||
|
.addr_i (slave_addr[Spi0]),
|
||||||
|
.data_i (slave_wdata[Spi0]),
|
||||||
|
.gnt_o (slave_gnt[Spi0]),
|
||||||
|
.rvalid_o (slave_rvalid[Spi0]),
|
||||||
|
.data_o (slave_rdata[Spi0])
|
||||||
|
);
|
||||||
|
|
||||||
`ifdef VERILATOR
|
`ifdef VERILATOR
|
||||||
assign slave_addr_mask[SimCtrl] = `SIM_CTRL_ADDR_MASK;
|
assign slave_addr_mask[SimCtrl] = `SIM_CTRL_ADDR_MASK;
|
||||||
assign slave_addr_base[SimCtrl] = `SIM_CTRL_ADDR_BASE;
|
assign slave_addr_base[SimCtrl] = `SIM_CTRL_ADDR_BASE;
|
||||||
// 8.仿真控制模块
|
// 9.仿真控制模块
|
||||||
sim_ctrl u_sim_ctrl(
|
sim_ctrl u_sim_ctrl(
|
||||||
.clk_i (clk),
|
.clk_i (clk),
|
||||||
.rst_ni (ndmreset_n),
|
.rst_ni (ndmreset_n),
|
||||||
|
|
Loading…
Reference in New Issue