Add SPI Engine framework
SPI Engine is a highly flexible and powerful SPI controller framework. It consist out of multiple sub-modules which communicate over well defined interfaces. This allows a high degree of flexibility and re-usability while at the same time staying highly customizable and easily extensible. Currently included are four components: * SPI Engine execution module: The excution module is responsible for handling the low-level physical interface SPI logic. * SPI Engine AXI interface module: The AXI interface module allows memory mapped acccess to a SPI bus control stream and can be used to implement a software driver that controls the SPI bus. * SPI Engine offload module: The offload module allows to store a predefined SPI Engine command and data stream which will be send out when a external trigger signal is asserted. * SPI Engine interconnect module: The interconnect module allows to combine multiple control streams into a single stream giving multiple control modules access to a execution module. For more information see: http://wiki.analog.com/resources/fpga/peripherals/spi_engine Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>main
parent
a5b452cc27
commit
e6b58e8a20
|
@ -41,6 +41,10 @@ clean:
|
|||
make -C axi_spdif_tx clean
|
||||
make -C controllerperipheralhdladi_pcore clean
|
||||
make -C cordic_demod clean
|
||||
make -C spi_engine/axi_spi_engine clean
|
||||
make -C spi_engine/spi_engine_execution clean
|
||||
make -C spi_engine/spi_engine_interconnect clean
|
||||
make -C spi_engine/spi_engine_offload clean
|
||||
make -C util_adc_pack clean
|
||||
make -C util_adcfifo clean
|
||||
make -C util_axis_fifo clean
|
||||
|
@ -94,6 +98,10 @@ lib:
|
|||
-make -C axi_spdif_tx
|
||||
-make -C controllerperipheralhdladi_pcore
|
||||
-make -C cordic_demod
|
||||
-make -C spi_engine/axi_spi_engine
|
||||
-make -C spi_engine/spi_engine_execution
|
||||
-make -C spi_engine/spi_engine_interconnect
|
||||
-make -C spi_engine/spi_engine_offload
|
||||
-make -C util_adc_pack
|
||||
-make -C util_adcfifo
|
||||
-make -C util_axis_fifo
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
####################################################################################
|
||||
####################################################################################
|
||||
## Copyright 2011(c) Analog Devices, Inc.
|
||||
## Auto-generated, do not modify!
|
||||
####################################################################################
|
||||
####################################################################################
|
||||
|
||||
M_DEPS := axi_spi_engine_ip.tcl
|
||||
M_DEPS += ../../scripts/adi_env.tcl
|
||||
M_DEPS += ../../scripts/adi_ip.tcl
|
||||
M_DEPS += axi_spi_engine.v
|
||||
M_DEPS += ../../common/sync_bits.v
|
||||
M_DEPS += ../../common/sync_gray.v
|
||||
M_DEPS += ../../common/up_axi.v
|
||||
M_DEPS += ../../common/ad_rst.v
|
||||
M_DEPS += ../../util_axis_fifo/util_axis_fifo.xpr
|
||||
|
||||
M_VIVADO := vivado -mode batch -source
|
||||
|
||||
M_FLIST := *.cache
|
||||
M_FLIST += *.data
|
||||
M_FLIST += *.xpr
|
||||
M_FLIST += *.log
|
||||
M_FLIST += component.xml
|
||||
M_FLIST += *.jou
|
||||
M_FLIST += xgui
|
||||
M_FLIST += .Xil
|
||||
|
||||
|
||||
|
||||
.PHONY: all dep clean clean-all
|
||||
all: dep axi_spi_engine.xpr
|
||||
|
||||
|
||||
clean:clean-all
|
||||
|
||||
|
||||
clean-all:
|
||||
rm -rf $(M_FLIST)
|
||||
|
||||
|
||||
axi_spi_engine.xpr: $(M_DEPS)
|
||||
rm -rf $(M_FLIST)
|
||||
$(M_VIVADO) axi_spi_engine_ip.tcl >> axi_spi_engine_ip.log 2>&1
|
||||
|
||||
dep:
|
||||
make -C ../../util_axis_fifo
|
||||
####################################################################################
|
||||
####################################################################################
|
|
@ -0,0 +1,335 @@
|
|||
|
||||
module axi_spi_engine (
|
||||
// Slave AXI interface
|
||||
input s_axi_aclk,
|
||||
input s_axi_aresetn,
|
||||
|
||||
input s_axi_awvalid,
|
||||
input [31:0] s_axi_awaddr,
|
||||
output s_axi_awready,
|
||||
input [2:0] s_axi_awprot,
|
||||
input s_axi_wvalid,
|
||||
input [31:0] s_axi_wdata,
|
||||
input [ 3:0] s_axi_wstrb,
|
||||
output s_axi_wready,
|
||||
output s_axi_bvalid,
|
||||
output [ 1:0] s_axi_bresp,
|
||||
input s_axi_bready,
|
||||
input s_axi_arvalid,
|
||||
input [31:0] s_axi_araddr,
|
||||
output s_axi_arready,
|
||||
input [2:0] s_axi_arprot,
|
||||
output s_axi_rvalid,
|
||||
input s_axi_rready,
|
||||
output [ 1:0] s_axi_rresp,
|
||||
output [31:0] s_axi_rdata,
|
||||
|
||||
output reg irq,
|
||||
|
||||
|
||||
// SPI signals
|
||||
input spi_clk,
|
||||
|
||||
output spi_resetn,
|
||||
|
||||
input cmd_ready,
|
||||
output cmd_valid,
|
||||
output [15:0] cmd_data,
|
||||
|
||||
input sdo_data_ready,
|
||||
output sdo_data_valid,
|
||||
output [7:0] sdo_data,
|
||||
|
||||
output sdi_data_ready,
|
||||
input sdi_data_valid,
|
||||
input [7:0] sdi_data,
|
||||
|
||||
output sync_ready,
|
||||
input sync_valid,
|
||||
input [7:0] sync_data,
|
||||
|
||||
// Offload ctrl signals
|
||||
output offload0_cmd_wr_en,
|
||||
output [15:0] offload0_cmd_wr_data,
|
||||
|
||||
output offload0_sdo_wr_en,
|
||||
output [7:0] offload0_sdo_wr_data,
|
||||
|
||||
output reg offload0_mem_reset,
|
||||
output reg offload0_enable,
|
||||
input offload0_enabled
|
||||
);
|
||||
|
||||
parameter CMD_FIFO_ADDRESS_WIDTH = 4;
|
||||
parameter SDO_FIFO_ADDRESS_WIDTH = 5;
|
||||
parameter SDI_FIFO_ADDRESS_WIDTH = 5;
|
||||
|
||||
parameter ASYNC_SPI_CLK = 0;
|
||||
|
||||
parameter NUM_OFFLOAD = 0;
|
||||
|
||||
parameter OFFLOAD0_CMD_MEM_ADDR_WIDTH = 4;
|
||||
parameter OFFLOAD0_SDO_MEM_ADDR_WIDTH = 4;
|
||||
|
||||
parameter PCORE_ID = 'h00;
|
||||
localparam PCORE_VERSION = 'h010061;
|
||||
|
||||
wire [CMD_FIFO_ADDRESS_WIDTH:0] cmd_fifo_room;
|
||||
wire cmd_fifo_almost_empty;
|
||||
|
||||
wire [15:0] cmd_fifo_in_data;
|
||||
wire cmd_fifo_in_ready;
|
||||
wire cmd_fifo_in_valid;
|
||||
|
||||
wire [SDO_FIFO_ADDRESS_WIDTH:0] sdo_fifo_room;
|
||||
wire sdo_fifo_almost_empty;
|
||||
|
||||
wire [7:0] sdo_fifo_in_data;
|
||||
wire sdo_fifo_in_ready;
|
||||
wire sdo_fifo_in_valid;
|
||||
|
||||
wire [SDI_FIFO_ADDRESS_WIDTH:0] sdi_fifo_level;
|
||||
wire sdi_fifo_almost_full;
|
||||
|
||||
wire [7:0] sdi_fifo_out_data;
|
||||
wire sdi_fifo_out_ready;
|
||||
wire sdi_fifo_out_valid;
|
||||
|
||||
reg up_reset = 1'b1;
|
||||
wire up_resetn = ~up_reset;
|
||||
|
||||
reg [31:0] up_rdata = 'd0;
|
||||
reg up_wack = 1'b0;
|
||||
reg up_rack = 1'b0;
|
||||
wire up_wreq;
|
||||
wire up_rreq;
|
||||
wire [31:0] up_wdata;
|
||||
wire [ 7:0] up_waddr;
|
||||
wire [ 7:0] up_raddr;
|
||||
|
||||
// Scratch register
|
||||
reg [31:0] up_scratch = 'h00;
|
||||
|
||||
reg [7:0] sync_id = 'h00;
|
||||
reg sync_id_pending = 1'b0;
|
||||
|
||||
up_axi #(
|
||||
.PCORE_ADDR_WIDTH (8)
|
||||
) i_up_axi (
|
||||
.up_rstn(s_axi_aresetn),
|
||||
.up_clk(s_axi_aclk),
|
||||
.up_axi_awvalid(s_axi_awvalid),
|
||||
.up_axi_awaddr(s_axi_awaddr),
|
||||
.up_axi_awready(s_axi_awready),
|
||||
.up_axi_wvalid(s_axi_wvalid),
|
||||
.up_axi_wdata(s_axi_wdata),
|
||||
.up_axi_wstrb(s_axi_wstrb),
|
||||
.up_axi_wready(s_axi_wready),
|
||||
.up_axi_bvalid(s_axi_bvalid),
|
||||
.up_axi_bresp(s_axi_bresp),
|
||||
.up_axi_bready(s_axi_bready),
|
||||
.up_axi_arvalid(s_axi_arvalid),
|
||||
.up_axi_araddr(s_axi_araddr),
|
||||
.up_axi_arready(s_axi_arready),
|
||||
.up_axi_rvalid(s_axi_rvalid),
|
||||
.up_axi_rresp(s_axi_rresp),
|
||||
.up_axi_rdata(s_axi_rdata),
|
||||
.up_axi_rready(s_axi_rready),
|
||||
.up_wreq(up_wreq),
|
||||
.up_waddr(up_waddr),
|
||||
.up_wdata(up_wdata),
|
||||
.up_wack(up_wack),
|
||||
.up_rreq(up_rreq),
|
||||
.up_raddr(up_raddr),
|
||||
.up_rdata(up_rdata),
|
||||
.up_rack(up_rack)
|
||||
);
|
||||
|
||||
// IRQ handling
|
||||
reg [3:0] up_irq_mask = 'h0;
|
||||
wire [3:0] up_irq_source;
|
||||
wire [3:0] up_irq_pending;
|
||||
|
||||
assign up_irq_source = {
|
||||
sync_id_pending,
|
||||
sdi_fifo_almost_full,
|
||||
sdo_fifo_almost_empty,
|
||||
cmd_fifo_almost_empty
|
||||
};
|
||||
|
||||
assign up_irq_pending = up_irq_mask & up_irq_source;
|
||||
|
||||
always @(posedge s_axi_aclk) begin
|
||||
if (s_axi_aresetn == 1'b0)
|
||||
irq <= 1'b0;
|
||||
else
|
||||
irq <= |up_irq_pending;
|
||||
end
|
||||
|
||||
always @(posedge s_axi_aclk) begin
|
||||
if (s_axi_aresetn == 1'b0) begin
|
||||
up_wack <= 1'b0;
|
||||
up_scratch <= 'h00;
|
||||
up_reset <= 1'b1;
|
||||
up_irq_mask <= 'h00;
|
||||
offload0_enable <= 1'b0;
|
||||
offload0_mem_reset <= 1'b0;
|
||||
end else begin
|
||||
up_wack <= up_wreq;
|
||||
offload0_mem_reset <= 1'b0;
|
||||
if (up_wreq) begin
|
||||
case (up_waddr)
|
||||
8'h02: up_scratch <= up_wdata;
|
||||
8'h10: up_reset <= up_wdata;
|
||||
8'h20: up_irq_mask <= up_wdata;
|
||||
8'h40: offload0_enable <= up_wdata[0];
|
||||
8'h42: offload0_mem_reset <= up_wdata[0];
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge s_axi_aclk) begin
|
||||
if (s_axi_aresetn == 1'b0) begin
|
||||
up_rack <= 'd0;
|
||||
end else begin
|
||||
up_rack <= up_rreq;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge s_axi_aclk) begin
|
||||
case (up_raddr)
|
||||
8'h00: up_rdata <= PCORE_VERSION;
|
||||
8'h01: up_rdata <= PCORE_ID;
|
||||
8'h02: up_rdata <= up_scratch;
|
||||
8'h10: up_rdata <= up_reset;
|
||||
8'h20: up_rdata <= up_irq_mask;
|
||||
8'h21: up_rdata <= up_irq_pending;
|
||||
8'h22: up_rdata <= up_irq_source;
|
||||
8'h30: up_rdata <= sync_id;
|
||||
8'h34: up_rdata <= cmd_fifo_room;
|
||||
8'h35: up_rdata <= sdo_fifo_room;
|
||||
8'h36: up_rdata <= sdi_fifo_level;
|
||||
8'h3a: up_rdata <= sdi_fifo_out_data;
|
||||
8'h3c: up_rdata <= sdi_fifo_out_data; /* PEEK register */
|
||||
8'h40: up_rdata <= {offload0_enable};
|
||||
8'h41: up_rdata <= {offload0_enabled};
|
||||
default: up_rdata <= 'h00;
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge s_axi_aclk) begin
|
||||
if (up_resetn == 1'b0) begin
|
||||
sync_id <= 'h00;
|
||||
sync_id_pending <= 1'b0;
|
||||
end else begin
|
||||
if (sync_valid == 1'b1) begin
|
||||
sync_id <= sync_data;
|
||||
sync_id_pending <= 1'b1;
|
||||
end else if (up_wreq == 1'b1 && up_waddr == 8'h21 && up_wdata[3] == 1'b1) begin
|
||||
sync_id_pending <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign sync_ready = 1'b1;
|
||||
|
||||
generate if (ASYNC_SPI_CLK) begin
|
||||
|
||||
wire spi_reset;
|
||||
ad_rst i_spi_resetn (
|
||||
.preset(up_reset),
|
||||
.clk(spi_clk),
|
||||
.rst(spi_reset)
|
||||
);
|
||||
assign spi_resetn = ~spi_reset;
|
||||
end else begin
|
||||
assign spi_resetn = ~up_reset;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
/* Evaluates to true if FIFO level/room is 3/4 or above */
|
||||
`define axi_spi_engine_check_watermark(x, n) \
|
||||
(x[n] == 1'b1 || x[n-1:n-2] == 2'b11)
|
||||
|
||||
assign cmd_fifo_in_valid = up_wreq == 1'b1 && up_waddr == 8'h38;
|
||||
assign cmd_fifo_in_data = up_wdata[15:0];
|
||||
assign cmd_fifo_almost_empty =
|
||||
`axi_spi_engine_check_watermark(cmd_fifo_room, CMD_FIFO_ADDRESS_WIDTH);
|
||||
|
||||
util_axis_fifo #(
|
||||
.C_DATA_WIDTH(16),
|
||||
.C_CLKS_ASYNC(ASYNC_SPI_CLK),
|
||||
.C_ADDRESS_WIDTH(CMD_FIFO_ADDRESS_WIDTH),
|
||||
.C_S_AXIS_REGISTERED(0)
|
||||
) i_cmd_fifo (
|
||||
.s_axis_aclk(s_axi_aclk),
|
||||
.s_axis_aresetn(up_resetn),
|
||||
.s_axis_ready(cmd_fifo_in_ready),
|
||||
.s_axis_valid(cmd_fifo_in_valid),
|
||||
.s_axis_data(cmd_fifo_in_data),
|
||||
.s_axis_room(cmd_fifo_room),
|
||||
|
||||
.m_axis_aclk(spi_clk),
|
||||
.m_axis_aresetn(spi_resetn),
|
||||
.m_axis_ready(cmd_ready),
|
||||
.m_axis_valid(cmd_valid),
|
||||
.m_axis_data(cmd_data)
|
||||
);
|
||||
|
||||
assign sdo_fifo_in_valid = up_wreq == 1'b1 && up_waddr == 8'h39;
|
||||
assign sdo_fifo_in_data = up_wdata[7:0];
|
||||
assign sdo_fifo_almost_empty =
|
||||
`axi_spi_engine_check_watermark(sdo_fifo_room, SDO_FIFO_ADDRESS_WIDTH);
|
||||
|
||||
util_axis_fifo #(
|
||||
.C_DATA_WIDTH(8),
|
||||
.C_CLKS_ASYNC(ASYNC_SPI_CLK),
|
||||
.C_ADDRESS_WIDTH(SDO_FIFO_ADDRESS_WIDTH),
|
||||
.C_S_AXIS_REGISTERED(0)
|
||||
) i_sdo_fifo (
|
||||
.s_axis_aclk(s_axi_aclk),
|
||||
.s_axis_aresetn(up_resetn),
|
||||
.s_axis_ready(sdo_fifo_in_ready),
|
||||
.s_axis_valid(sdo_fifo_in_valid),
|
||||
.s_axis_data(sdo_fifo_in_data),
|
||||
.s_axis_room(sdo_fifo_room),
|
||||
|
||||
.m_axis_aclk(spi_clk),
|
||||
.m_axis_aresetn(spi_resetn),
|
||||
.m_axis_ready(sdo_data_ready),
|
||||
.m_axis_valid(sdo_data_valid),
|
||||
.m_axis_data(sdo_data)
|
||||
);
|
||||
|
||||
assign sdi_fifo_out_ready = up_rreq == 1'b1 && up_raddr == 8'h3a;
|
||||
assign sdi_fifo_almost_full =
|
||||
`axi_spi_engine_check_watermark(sdi_fifo_level, SDI_FIFO_ADDRESS_WIDTH);
|
||||
|
||||
util_axis_fifo #(
|
||||
.C_DATA_WIDTH(8),
|
||||
.C_CLKS_ASYNC(ASYNC_SPI_CLK),
|
||||
.C_ADDRESS_WIDTH(SDI_FIFO_ADDRESS_WIDTH),
|
||||
.C_S_AXIS_REGISTERED(0)
|
||||
) i_sdi_fifo (
|
||||
.s_axis_aclk(spi_clk),
|
||||
.s_axis_aresetn(spi_resetn),
|
||||
.s_axis_ready(sdi_data_ready),
|
||||
.s_axis_valid(sdi_data_valid),
|
||||
.s_axis_data(sdi_data),
|
||||
|
||||
.m_axis_aclk(s_axi_aclk),
|
||||
.m_axis_aresetn(up_resetn),
|
||||
.m_axis_ready(sdi_fifo_out_ready),
|
||||
.m_axis_valid(sdi_fifo_out_valid),
|
||||
.m_axis_data(sdi_fifo_out_data),
|
||||
.m_axis_level(sdi_fifo_level)
|
||||
);
|
||||
|
||||
assign offload0_cmd_wr_en = up_wreq == 1'b1 && up_waddr == 8'h44;
|
||||
assign offload0_cmd_wr_data = up_wdata[15:0];
|
||||
|
||||
assign offload0_sdo_wr_en = up_wreq == 1'b1 && up_waddr == 8'h45;
|
||||
assign offload0_sdo_wr_data = up_wdata[7:0];
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,62 @@
|
|||
# ip
|
||||
|
||||
source ../../scripts/adi_env.tcl
|
||||
source $ad_hdl_dir/library/scripts/adi_ip.tcl
|
||||
|
||||
adi_ip_create axi_spi_engine
|
||||
adi_ip_files axi_spi_engine [list \
|
||||
"axi_spi_engine.v" \
|
||||
"$ad_hdl_dir/library/common/sync_bits.v" \
|
||||
"$ad_hdl_dir/library/common/sync_gray.v" \
|
||||
"$ad_hdl_dir/library/common/up_axi.v" \
|
||||
"$ad_hdl_dir/library/common/ad_rst.v" \
|
||||
]
|
||||
|
||||
adi_ip_properties axi_spi_engine
|
||||
# Remove auto inferred interfaces
|
||||
ipx::remove_bus_interface offload0_mem_signal_reset [ipx::current_core]
|
||||
ipx::remove_bus_interface spi_signal_clock [ipx::current_core]
|
||||
ipx::remove_bus_interface spi_signal_reset [ipx::current_core]
|
||||
|
||||
adi_ip_add_core_dependencies { \
|
||||
analog.com:user:util_axis_fifo:1.0 \
|
||||
}
|
||||
|
||||
set_property physical_name {s_axi_aclk} [ipx::get_port_map CLK \
|
||||
[ipx::get_bus_interface s_axi_signal_clock [ipx::current_core]]]
|
||||
|
||||
adi_add_bus "spi_engine_ctrl" "master" \
|
||||
"analog.com:interface:spi_engine_ctrl_rtl:1.0" \
|
||||
"analog.com:interface:spi_engine_ctrl:1.0" \
|
||||
{
|
||||
{"cmd_ready" "CMD_READY"} \
|
||||
{"cmd_valid" "CMD_VALID"} \
|
||||
{"cmd_data" "CMD_DATA"} \
|
||||
{"sdo_data_ready" "SDO_READY"} \
|
||||
{"sdo_data_valid" "SDO_VALID"} \
|
||||
{"sdo_data" "SDO_DATA"} \
|
||||
{"sdi_data_ready" "SDI_READY"} \
|
||||
{"sdi_data_valid" "SDI_VALID"} \
|
||||
{"sdi_data" "SDI_DATA"} \
|
||||
{"sync_ready" "SYNC_READY"} \
|
||||
{"sync_valid" "SYNC_VALID"} \
|
||||
{"sync_data" "SYNC_DATA"} \
|
||||
}
|
||||
adi_add_bus_clock "spi_clk" "spi_engine_ctrl" "spi_resetn" "master"
|
||||
|
||||
adi_add_bus "spi_engine_offload_ctrl0" "master" \
|
||||
"analog.com:interface:spi_engine_offload_ctrl_rtl:1.0" \
|
||||
"analog.com:interface:spi_engine_offload_ctrl:1.0" \
|
||||
{ \
|
||||
{ "offload0_cmd_wr_en" "CMD_WR_EN"} \
|
||||
{ "offload0_cmd_wr_data" "CMD_WR_DATA"} \
|
||||
{ "offload0_sdo_wr_en" "SDO_WR_EN"} \
|
||||
{ "offload0_sdo_wr_data" "SDO_WR_DATA"} \
|
||||
{ "offload0_enable" "ENABLE"} \
|
||||
{ "offload0_enabled" "ENABLED"} \
|
||||
{ "offload0_mem_reset" "MEM_RESET"} \
|
||||
}
|
||||
|
||||
adi_add_bus_clock "s_axi_aclk" "spi_engine_offload_ctrl0:s_axi" "s_axi_aresetn"
|
||||
|
||||
ipx::save_core [ipx::current_core]
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<spirit:busDefinition xmlns:xilinx="http://www.xilinx.com"
|
||||
xmlns:spirit="http://www.spiritconsortium.org/XMLSchema/SPIRIT/1685-2009"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<spirit:vendor>analog.com</spirit:vendor>
|
||||
<spirit:library>interface</spirit:library>
|
||||
<spirit:name>spi_engine_ctrl</spirit:name>
|
||||
<spirit:version>1.0</spirit:version>
|
||||
<spirit:directConnection>false</spirit:directConnection>
|
||||
<spirit:isAddressable>false</spirit:isAddressable>
|
||||
<spirit:maxMasters>1</spirit:maxMasters>
|
||||
<spirit:maxSlaves>1</spirit:maxSlaves>
|
||||
</spirit:busDefinition>
|
|
@ -0,0 +1,189 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<spirit:abstractionDefinition xmlns:xilinx="http://www.xilinx.com"
|
||||
xmlns:spirit="http://www.spiritconsortium.org/XMLSchema/SPIRIT/1685-2009"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<spirit:vendor>analog.com</spirit:vendor>
|
||||
<spirit:library>interface</spirit:library>
|
||||
<spirit:name>spi_engine_ctrl_rtl</spirit:name>
|
||||
<spirit:version>1.0</spirit:version>
|
||||
<spirit:busType spirit:vendor="analog.com"
|
||||
spirit:library="interface"
|
||||
spirit:name="spi_engine_ctrl"
|
||||
spirit:version="1.0"/>
|
||||
<spirit:ports>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>CMD_READY</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>CMD_VALID</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>CMD_DATA</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>16</spirit:width>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>16</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SDO_READY</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SDO_VALID</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SDO_DATA</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>8</spirit:width>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>8</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SDI_READY</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>out</spirit:direction>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SDI_VALID</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>out</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SDI_DATA</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>8</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>8</spirit:width>
|
||||
<spirit:direction>out</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SYNC_READY</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>out</spirit:direction>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SYNC_VALID</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>out</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SYNC_DATA</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>8</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>8</spirit:width>
|
||||
<spirit:direction>out</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
</spirit:ports>
|
||||
</spirit:abstractionDefinition>
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<spirit:busDefinition xmlns:xilinx="http://www.xilinx.com"
|
||||
xmlns:spirit="http://www.spiritconsortium.org/XMLSchema/SPIRIT/1685-2009"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<spirit:vendor>analog.com</spirit:vendor>
|
||||
<spirit:library>interface</spirit:library>
|
||||
<spirit:name>spi_engine_offload_ctrl</spirit:name>
|
||||
<spirit:version>1.0</spirit:version>
|
||||
<spirit:directConnection>false</spirit:directConnection>
|
||||
<spirit:isAddressable>false</spirit:isAddressable>
|
||||
<spirit:maxMasters>1</spirit:maxMasters>
|
||||
<spirit:maxSlaves>1</spirit:maxSlaves>
|
||||
</spirit:busDefinition>
|
|
@ -0,0 +1,113 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<spirit:abstractionDefinition xmlns:xilinx="http://www.xilinx.com"
|
||||
xmlns:spirit="http://www.spiritconsortium.org/XMLSchema/SPIRIT/1685-2009"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<spirit:vendor>analog.com</spirit:vendor>
|
||||
<spirit:library>interface</spirit:library>
|
||||
<spirit:name>spi_engine_offload_ctrl_rtl</spirit:name>
|
||||
<spirit:version>1.0</spirit:version>
|
||||
<spirit:busType spirit:vendor="analog.com"
|
||||
spirit:library="interface"
|
||||
spirit:name="spi_engine_offload_ctrl"
|
||||
spirit:version="1.0"/>
|
||||
<spirit:ports>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>CMD_WR_EN</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>CMD_WR_DATA</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>16</spirit:width>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>16</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SDO_WR_EN</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SDO_WR_DATA</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>8</spirit:width>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>8</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>ENABLE</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>MEM_RESET</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>ENABLED</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
</spirit:ports>
|
||||
</spirit:abstractionDefinition>
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<spirit:busDefinition xmlns:xilinx="http://www.xilinx.com"
|
||||
xmlns:spirit="http://www.spiritconsortium.org/XMLSchema/SPIRIT/1685-2009"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<spirit:vendor>analog.com</spirit:vendor>
|
||||
<spirit:library>interface</spirit:library>
|
||||
<spirit:name>spi_master</spirit:name>
|
||||
<spirit:version>1.0</spirit:version>
|
||||
<spirit:directConnection>false</spirit:directConnection>
|
||||
<spirit:isAddressable>false</spirit:isAddressable>
|
||||
<spirit:maxMasters>1</spirit:maxMasters>
|
||||
<spirit:maxSlaves>1</spirit:maxSlaves>
|
||||
</spirit:busDefinition>
|
|
@ -0,0 +1,85 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<spirit:abstractionDefinition xmlns:xilinx="http://www.xilinx.com"
|
||||
xmlns:spirit="http://www.spiritconsortium.org/XMLSchema/SPIRIT/1685-2009"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<spirit:vendor>analog.com</spirit:vendor>
|
||||
<spirit:library>interface</spirit:library>
|
||||
<spirit:name>spi_master_rtl</spirit:name>
|
||||
<spirit:version>1.0</spirit:version>
|
||||
<spirit:busType spirit:vendor="analog.com"
|
||||
spirit:library="interface"
|
||||
spirit:name="spi_master"
|
||||
spirit:version="1.0"/>
|
||||
<spirit:ports>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SCLK</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:presence>required</spirit:presence>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SDI</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:width>1</spirit:width>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SDO</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:width>1</spirit:width>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>SDO_T</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:width>1</spirit:width>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>THREE_WIRE</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onMaster>
|
||||
<spirit:width>1</spirit:width>
|
||||
</spirit:onMaster>
|
||||
<spirit:onSlave>
|
||||
<spirit:width>1</spirit:width>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
<spirit:port>
|
||||
<spirit:logicalName>CS</spirit:logicalName>
|
||||
<spirit:wire>
|
||||
<spirit:onSlave>
|
||||
<spirit:direction>in</spirit:direction>
|
||||
</spirit:onSlave>
|
||||
</spirit:wire>
|
||||
</spirit:port>
|
||||
</spirit:ports>
|
||||
</spirit:abstractionDefinition>
|
|
@ -0,0 +1,42 @@
|
|||
####################################################################################
|
||||
####################################################################################
|
||||
## Copyright 2011(c) Analog Devices, Inc.
|
||||
## Auto-generated, do not modify!
|
||||
####################################################################################
|
||||
####################################################################################
|
||||
|
||||
M_DEPS := spi_engine_execution_ip.tcl
|
||||
M_DEPS += ../../scripts/adi_env.tcl
|
||||
M_DEPS += ../../scripts/adi_ip.tcl
|
||||
M_DEPS += spi_engine_execution.v
|
||||
|
||||
M_VIVADO := vivado -mode batch -source
|
||||
|
||||
M_FLIST := *.cache
|
||||
M_FLIST += *.data
|
||||
M_FLIST += *.xpr
|
||||
M_FLIST += *.log
|
||||
M_FLIST += component.xml
|
||||
M_FLIST += *.jou
|
||||
M_FLIST += xgui
|
||||
M_FLIST += .Xil
|
||||
|
||||
|
||||
|
||||
.PHONY: all clean clean-all
|
||||
all: spi_engine_execution.xpr
|
||||
|
||||
|
||||
clean:clean-all
|
||||
|
||||
|
||||
clean-all:
|
||||
rm -rf $(M_FLIST)
|
||||
|
||||
|
||||
spi_engine_execution.xpr: $(M_DEPS)
|
||||
rm -rf $(M_FLIST)
|
||||
$(M_VIVADO) spi_engine_execution_ip.tcl >> spi_engine_execution_ip.log 2>&1
|
||||
|
||||
####################################################################################
|
||||
####################################################################################
|
|
@ -0,0 +1,313 @@
|
|||
|
||||
module spi_engine_execution (
|
||||
input clk,
|
||||
input resetn,
|
||||
|
||||
output reg active,
|
||||
|
||||
output cmd_ready,
|
||||
input cmd_valid,
|
||||
input [15:0] cmd,
|
||||
|
||||
input sdo_data_valid,
|
||||
output reg sdo_data_ready,
|
||||
input [7:0] sdo_data,
|
||||
|
||||
input sdi_data_ready,
|
||||
output reg sdi_data_valid,
|
||||
output [7:0] sdi_data,
|
||||
|
||||
input sync_ready,
|
||||
output reg sync_valid,
|
||||
output [7:0] sync,
|
||||
|
||||
output reg sclk,
|
||||
output sdo,
|
||||
output reg sdo_t,
|
||||
input sdi,
|
||||
output reg [NUM_CS-1:0] cs,
|
||||
output reg three_wire
|
||||
);
|
||||
|
||||
parameter NUM_CS = 1;
|
||||
parameter DEFAULT_SPI_CFG = 0;
|
||||
parameter DEFAULT_CLK_DIV = 0;
|
||||
|
||||
localparam CMD_TRANSFER = 2'b00;
|
||||
localparam CMD_CHIPSELECT = 2'b01;
|
||||
localparam CMD_WRITE = 2'b10;
|
||||
localparam CMD_MISC = 2'b11;
|
||||
|
||||
localparam MISC_SYNC = 1'b0;
|
||||
localparam MISC_SLEEP = 1'b1;
|
||||
|
||||
localparam REG_CLK_DIV = 1'b0;
|
||||
localparam REG_CONFIG = 1'b1;
|
||||
|
||||
reg idle;
|
||||
|
||||
reg [7:0] clk_div_counter = 'h00;
|
||||
reg [7:0] clk_div_counter_next = 'h00;
|
||||
reg clk_div_last;
|
||||
|
||||
reg [11:0] counter = 'h00;
|
||||
|
||||
wire [7:0] sleep_counter = counter[11:4];
|
||||
wire [1:0] cs_sleep_counter = counter[5:4];
|
||||
wire [2:0] cs_sleep_counter2 = counter[6:4];
|
||||
wire [2:0] bit_counter = counter[3:1];
|
||||
wire [7:0] transfer_counter = counter[11:4];
|
||||
wire ntx_rx = counter[0];
|
||||
|
||||
reg trigger = 1'b0;
|
||||
reg trigger_next = 1'b0;
|
||||
reg wait_for_io = 1'b0;
|
||||
reg transfer_active = 1'b0;
|
||||
|
||||
wire last_bit;
|
||||
wire first_bit;
|
||||
reg last_transfer;
|
||||
wire end_of_word;
|
||||
|
||||
assign first_bit = bit_counter == 'h0;
|
||||
assign last_bit = bit_counter == 'h7;
|
||||
assign end_of_word = last_bit == 1'b1 && ntx_rx == 1'b1 && clk_div_last == 1'b1;
|
||||
|
||||
reg [15:0] cmd_d1;
|
||||
|
||||
reg cpha = DEFAULT_SPI_CFG[0];
|
||||
reg cpol = DEFAULT_SPI_CFG[1];
|
||||
reg [7:0] clk_div = DEFAULT_CLK_DIV;
|
||||
|
||||
wire sdo_enabled = cmd_d1[8];
|
||||
wire sdi_enabled = cmd_d1[9];
|
||||
|
||||
reg [8:0] data_shift = 'h0;
|
||||
|
||||
wire [1:0] inst = cmd[13:12];
|
||||
wire [1:0] inst_d1 = cmd_d1[13:12];
|
||||
|
||||
wire exec_cmd = cmd_ready && cmd_valid;
|
||||
wire exec_transfer_cmd = exec_cmd && inst == CMD_TRANSFER;
|
||||
wire exec_write_cmd = exec_cmd && inst == CMD_WRITE;
|
||||
wire exec_chipselect_cmd = exec_cmd && inst == CMD_CHIPSELECT;
|
||||
wire exec_misc_cmd = exec_cmd && inst == CMD_MISC;
|
||||
wire exec_sync_cmd = exec_misc_cmd && cmd[8] == MISC_SYNC;
|
||||
|
||||
assign cmd_ready = idle;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (cmd_ready)
|
||||
cmd_d1 <= cmd;
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (resetn == 1'b0) begin
|
||||
active <= 1'b0;
|
||||
end else begin
|
||||
if (exec_cmd == 1'b1)
|
||||
active <= 1'b1;
|
||||
else if (sync_ready == 1'b1 && sync_valid == 1'b1)
|
||||
active <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (resetn == 1'b0) begin
|
||||
cpha <= DEFAULT_SPI_CFG[0];
|
||||
cpol <= DEFAULT_SPI_CFG[1];
|
||||
three_wire <= DEFAULT_SPI_CFG[2];
|
||||
clk_div <= DEFAULT_CLK_DIV;
|
||||
end else if (exec_write_cmd == 1'b1) begin
|
||||
if (cmd[8] == REG_CONFIG) begin
|
||||
cpha <= cmd[0];
|
||||
cpol <= cmd[1];
|
||||
three_wire <= cmd[2];
|
||||
end else if (cmd[8] == REG_CLK_DIV) begin
|
||||
clk_div <= cmd[7:0];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if ((clk_div_last == 1'b0 && idle == 1'b0 && wait_for_io == 1'b0 &&
|
||||
clk_div_counter == 'h01) || clk_div == 'h00)
|
||||
clk_div_last <= 1'b1;
|
||||
else
|
||||
clk_div_last <= 1'b0;
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (clk_div_last == 1'b1 || idle == 1'b1 || wait_for_io == 1'b1) begin
|
||||
clk_div_counter <= clk_div;
|
||||
trigger <= 1'b1;
|
||||
end else begin
|
||||
clk_div_counter <= clk_div_counter - 1'b1;
|
||||
trigger <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
wire trigger_tx = trigger == 1'b1 && ntx_rx == 1'b0;
|
||||
wire trigger_rx = trigger == 1'b1 && ntx_rx == 1'b1;
|
||||
|
||||
wire sleep_counter_compare = sleep_counter == cmd_d1[7:0] && clk_div_last == 1'b1;
|
||||
wire cs_sleep_counter_compare = cs_sleep_counter == cmd_d1[9:8] && clk_div_last == 1'b1;
|
||||
wire cs_sleep_counter_compare2 = cs_sleep_counter2 == {cmd_d1[9:8],1'b1} && clk_div_last == 1'b1;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (idle == 1'b1)
|
||||
counter <= 'h00;
|
||||
else if (clk_div_last == 1'b1 && wait_for_io == 1'b0)
|
||||
counter <= counter + (transfer_active ? 'h1 : 'h10);
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (resetn == 1'b0) begin
|
||||
idle <= 1'b1;
|
||||
end else begin
|
||||
if (exec_transfer_cmd || exec_chipselect_cmd || exec_misc_cmd) begin
|
||||
idle <= 1'b0;
|
||||
end else begin
|
||||
case (inst_d1)
|
||||
CMD_TRANSFER: begin
|
||||
if (transfer_active == 1'b0 && wait_for_io == 1'b0)
|
||||
idle <= 1'b1;
|
||||
end
|
||||
CMD_CHIPSELECT: begin
|
||||
if (cs_sleep_counter_compare2)
|
||||
idle <= 1'b1;
|
||||
end
|
||||
CMD_MISC: begin
|
||||
case (cmd_d1[8])
|
||||
MISC_SLEEP: begin
|
||||
if (sleep_counter_compare)
|
||||
idle <= 1'b1;
|
||||
end
|
||||
MISC_SYNC: begin
|
||||
if (sync_ready)
|
||||
idle <= 1'b1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (resetn == 1'b0) begin
|
||||
cs <= 'hff;
|
||||
end else if (inst_d1 == CMD_CHIPSELECT && cs_sleep_counter_compare == 1'b1) begin
|
||||
cs <= cmd_d1[NUM_CS-1:0];
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (resetn == 1'b0) begin
|
||||
sync_valid <= 1'b0;
|
||||
end else begin
|
||||
if (exec_sync_cmd == 1'b1) begin
|
||||
sync_valid <= 1'b1;
|
||||
end else if (sync_ready == 1'b1) begin
|
||||
sync_valid <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign sync = cmd_d1[7:0];
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (resetn == 1'b0)
|
||||
sdo_data_ready <= 1'b0;
|
||||
else if (sdo_enabled == 1'b1 && first_bit == 1'b1 && trigger_tx == 1'b1 &&
|
||||
transfer_active == 1'b1)
|
||||
sdo_data_ready <= 1'b1;
|
||||
else if (sdo_data_valid == 1'b1)
|
||||
sdo_data_ready <= 1'b0;
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (resetn == 1'b0)
|
||||
sdi_data_valid <= 1'b0;
|
||||
else if (sdi_enabled == 1'b1 && last_bit == 1'b1 && trigger_rx == 1'b1 &&
|
||||
transfer_active == 1'b1)
|
||||
sdi_data_valid <= 1'b1;
|
||||
else if (sdi_data_ready == 1'b1)
|
||||
sdi_data_valid <= 1'b0;
|
||||
end
|
||||
|
||||
wire io_ready1 = (sdi_data_valid == 1'b0 || sdi_data_ready == 1'b1) &&
|
||||
(sdo_enabled == 1'b0 || last_transfer == 1'b1 || sdo_data_valid == 1'b1);
|
||||
wire io_ready2 = (sdi_enabled == 1'b0 || sdi_data_ready == 1'b1) &&
|
||||
(sdo_enabled == 1'b0 || last_transfer == 1'b1 || sdo_data_valid == 1'b1);
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (idle == 1'b1) begin
|
||||
last_transfer <= 1'b0;
|
||||
end else if (trigger_tx == 1'b1 && transfer_active == 1'b1) begin
|
||||
if (transfer_counter == cmd_d1[7:0])
|
||||
last_transfer <= 1'b1;
|
||||
else
|
||||
last_transfer <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (resetn == 1'b0) begin
|
||||
transfer_active <= 1'b0;
|
||||
wait_for_io <= 1'b0;
|
||||
end else begin
|
||||
if (exec_transfer_cmd == 1'b1) begin
|
||||
wait_for_io <= 1'b1;
|
||||
transfer_active <= 1'b0;
|
||||
end else if (wait_for_io == 1'b1 && io_ready1 == 1'b1) begin
|
||||
wait_for_io <= 1'b0;
|
||||
if (last_transfer == 1'b0)
|
||||
transfer_active <= 1'b1;
|
||||
else
|
||||
transfer_active <= 1'b0;
|
||||
end else if (transfer_active == 1'b1 && end_of_word == 1'b1) begin
|
||||
if (last_transfer == 1'b1 || io_ready2 == 1'b0)
|
||||
transfer_active <= 1'b0;
|
||||
if (io_ready2 == 1'b0)
|
||||
wait_for_io <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (transfer_active == 1'b1 || wait_for_io == 1'b1)
|
||||
begin
|
||||
sdo_t <= ~sdo_enabled;
|
||||
end else begin
|
||||
sdo_t <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (transfer_active == 1'b1 && trigger_tx == 1'b1) begin
|
||||
if (first_bit == 1'b1)
|
||||
data_shift[8:1] <= sdo_data;
|
||||
else
|
||||
data_shift[8:1] <= data_shift[7:0];
|
||||
end
|
||||
end
|
||||
|
||||
assign sdo = data_shift[8];
|
||||
assign sdi_data = data_shift[7:0];
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (trigger_rx == 1'b1) begin
|
||||
data_shift[0] <= sdi;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (transfer_active == 1'b1) begin
|
||||
sclk <= cpol ^ cpha ^ ntx_rx;
|
||||
end else begin
|
||||
sclk <= cpol;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
source ../../scripts/adi_env.tcl
|
||||
source $ad_hdl_dir/library/scripts/adi_ip.tcl
|
||||
|
||||
adi_ip_create spi_engine_execution
|
||||
adi_ip_files spi_engine_execution [list \
|
||||
"spi_engine_execution.v" \
|
||||
]
|
||||
|
||||
adi_ip_properties_lite spi_engine_execution
|
||||
# Remove all inferred interfaces
|
||||
ipx::remove_all_bus_interface [ipx::current_core]
|
||||
|
||||
adi_add_bus "ctrl" "slave" \
|
||||
"analog.com:interface:spi_engine_ctrl_rtl:1.0" \
|
||||
"analog.com:interface:spi_engine_ctrl:1.0" \
|
||||
{
|
||||
{"cmd_ready" "CMD_READY"} \
|
||||
{"cmd_valid" "CMD_VALID"} \
|
||||
{"cmd" "CMD_DATA"} \
|
||||
{"sdo_data_ready" "SDO_READY"} \
|
||||
{"sdo_data_valid" "SDO_VALID"} \
|
||||
{"sdo_data" "SDO_DATA"} \
|
||||
{"sdi_data_ready" "SDI_READY"} \
|
||||
{"sdi_data_valid" "SDI_VALID"} \
|
||||
{"sdi_data" "SDI_DATA"} \
|
||||
{"sync_ready" "SYNC_READY"} \
|
||||
{"sync_valid" "SYNC_VALID"} \
|
||||
{"sync" "SYNC_DATA"} \
|
||||
}
|
||||
adi_add_bus_clock "clk" "ctrl" "resetn"
|
||||
|
||||
adi_add_bus "spi" "master" \
|
||||
"analog.com:interface:spi_master_rtl:1.0" \
|
||||
"analog.com:interface:spi_master:1.0" \
|
||||
{
|
||||
{"sclk" "SCLK"} \
|
||||
{"sdi" "SDI"} \
|
||||
{"sdo" "SDO"} \
|
||||
{"sdo_t" "SDO_T"} \
|
||||
{"three_wire" "THREE_WIRE"} \
|
||||
{"cs" "CS"} \
|
||||
}
|
||||
adi_add_bus_clock "clk" "spi" "resetn"
|
||||
|
||||
ipx::save_core [ipx::current_core]
|
|
@ -0,0 +1,42 @@
|
|||
####################################################################################
|
||||
####################################################################################
|
||||
## Copyright 2011(c) Analog Devices, Inc.
|
||||
## Auto-generated, do not modify!
|
||||
####################################################################################
|
||||
####################################################################################
|
||||
|
||||
M_DEPS := spi_engine_interconnect_ip.tcl
|
||||
M_DEPS += ../../scripts/adi_env.tcl
|
||||
M_DEPS += ../../scripts/adi_ip.tcl
|
||||
M_DEPS += spi_engine_interconnect.v
|
||||
|
||||
M_VIVADO := vivado -mode batch -source
|
||||
|
||||
M_FLIST := *.cache
|
||||
M_FLIST += *.data
|
||||
M_FLIST += *.xpr
|
||||
M_FLIST += *.log
|
||||
M_FLIST += component.xml
|
||||
M_FLIST += *.jou
|
||||
M_FLIST += xgui
|
||||
M_FLIST += .Xil
|
||||
|
||||
|
||||
|
||||
.PHONY: all clean clean-all
|
||||
all: spi_engine_interconnect.xpr
|
||||
|
||||
|
||||
clean:clean-all
|
||||
|
||||
|
||||
clean-all:
|
||||
rm -rf $(M_FLIST)
|
||||
|
||||
|
||||
spi_engine_interconnect.xpr: $(M_DEPS)
|
||||
rm -rf $(M_FLIST)
|
||||
$(M_VIVADO) spi_engine_interconnect_ip.tcl >> spi_engine_interconnect_ip.log 2>&1
|
||||
|
||||
####################################################################################
|
||||
####################################################################################
|
|
@ -0,0 +1,107 @@
|
|||
|
||||
|
||||
module spi_engine_interconnect (
|
||||
input clk,
|
||||
input resetn,
|
||||
|
||||
output m_cmd_valid,
|
||||
input m_cmd_ready,
|
||||
output [15:0] m_cmd_data,
|
||||
|
||||
output m_sdo_valid,
|
||||
input m_sdo_ready,
|
||||
output [7:0] m_sdo_data,
|
||||
|
||||
input m_sdi_valid,
|
||||
output m_sdi_ready,
|
||||
input [7:0] m_sdi_data,
|
||||
|
||||
input m_sync_valid,
|
||||
output m_sync_ready,
|
||||
input [7:0] m_sync,
|
||||
|
||||
|
||||
input s0_cmd_valid,
|
||||
output s0_cmd_ready,
|
||||
input [15:0] s0_cmd_data,
|
||||
|
||||
input s0_sdo_valid,
|
||||
output s0_sdo_ready,
|
||||
input [7:0] s0_sdo_data,
|
||||
|
||||
output s0_sdi_valid,
|
||||
input s0_sdi_ready,
|
||||
output [7:0] s0_sdi_data,
|
||||
|
||||
output s0_sync_valid,
|
||||
input s0_sync_ready,
|
||||
output [7:0] s0_sync,
|
||||
|
||||
|
||||
input s1_cmd_valid,
|
||||
output s1_cmd_ready,
|
||||
input [15:0] s1_cmd_data,
|
||||
|
||||
input s1_sdo_valid,
|
||||
output s1_sdo_ready,
|
||||
input [7:0] s1_sdo_data,
|
||||
|
||||
output s1_sdi_valid,
|
||||
input s1_sdi_ready,
|
||||
output [7:0] s1_sdi_data,
|
||||
|
||||
output s1_sync_valid,
|
||||
input s1_sync_ready,
|
||||
output [7:0] s1_sync
|
||||
);
|
||||
|
||||
reg s_active = 1'b0;
|
||||
|
||||
reg idle = 1'b1;
|
||||
|
||||
`define spi_engine_interconnect_mux(s0, s1) (idle == 1'b1 ? 1'b0 : (s_active == 1'b0 ? s0 : s1))
|
||||
|
||||
assign m_cmd_data = s_active == 1'b0 ? s0_cmd_data : s1_cmd_data;
|
||||
assign m_cmd_valid = `spi_engine_interconnect_mux(s0_cmd_valid, s1_cmd_valid);
|
||||
assign s0_cmd_ready = `spi_engine_interconnect_mux(m_cmd_ready, 1'b0);
|
||||
assign s1_cmd_ready = `spi_engine_interconnect_mux(1'b0, m_cmd_ready);
|
||||
|
||||
assign m_sdo_data = s_active == 1'b0 ? s0_sdo_data : s1_sdo_data;
|
||||
assign m_sdo_valid = `spi_engine_interconnect_mux(s0_sdo_valid, s1_sdo_valid);
|
||||
assign s0_sdo_ready = `spi_engine_interconnect_mux(m_sdo_ready, 1'b0);
|
||||
assign s1_sdo_ready = `spi_engine_interconnect_mux(1'b0, m_sdo_ready);
|
||||
|
||||
assign s0_sdi_data = m_sdi_data;
|
||||
assign s1_sdi_data = m_sdi_data;
|
||||
assign m_sdi_ready = `spi_engine_interconnect_mux(s0_sdi_ready, s1_sdi_ready);
|
||||
assign s0_sdi_valid = `spi_engine_interconnect_mux(m_sdi_valid, 1'b0);
|
||||
assign s1_sdi_valid = `spi_engine_interconnect_mux(1'b0, m_sdi_valid);
|
||||
|
||||
assign s0_sync = m_sync;
|
||||
assign s1_sync = m_sync;
|
||||
assign m_sync_ready = `spi_engine_interconnect_mux(s0_sync_ready, s1_sync_ready);
|
||||
assign s0_sync_valid = `spi_engine_interconnect_mux(m_sync_valid, 1'b0);
|
||||
assign s1_sync_valid = `spi_engine_interconnect_mux(1'b0, m_sync_valid);
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (idle == 1'b1) begin
|
||||
if (s0_cmd_valid)
|
||||
s_active <= 1'b0;
|
||||
else if (s1_cmd_valid)
|
||||
s_active <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (resetn == 1'b0) begin
|
||||
idle = 1'b1;
|
||||
end else begin
|
||||
if (m_sync_valid == 1'b1 && m_sync_ready == 1'b1) begin
|
||||
idle <= 1'b1;
|
||||
end else if (s0_cmd_valid == 1'b1 || s1_cmd_valid == 1'b1) begin
|
||||
idle <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
source ../../scripts/adi_env.tcl
|
||||
source $ad_hdl_dir/library/scripts/adi_ip.tcl
|
||||
|
||||
adi_ip_create spi_engine_interconnect
|
||||
adi_ip_files spi_engine_interconnect [list \
|
||||
"spi_engine_interconnect.v" \
|
||||
]
|
||||
|
||||
adi_ip_properties_lite spi_engine_interconnect
|
||||
# Remove all inferred interfaces
|
||||
ipx::remove_all_bus_interface [ipx::current_core]
|
||||
|
||||
adi_add_bus "m_ctrl" "master" \
|
||||
"analog.com:interface:spi_engine_ctrl_rtl:1.0" \
|
||||
"analog.com:interface:spi_engine_ctrl:1.0" \
|
||||
{ \
|
||||
{"m_cmd_ready" "CMD_READY"} \
|
||||
{"m_cmd_valid" "CMD_VALID"} \
|
||||
{"m_cmd_data" "CMD_DATA"} \
|
||||
{"m_sdo_ready" "SDO_READY"} \
|
||||
{"m_sdo_valid" "SDO_VALID"} \
|
||||
{"m_sdo_data" "SDO_DATA"} \
|
||||
{"m_sdi_ready" "SDI_READY"} \
|
||||
{"m_sdi_valid" "SDI_VALID"} \
|
||||
{"m_sdi_data" "SDI_DATA"} \
|
||||
{"m_sync_ready" "SYNC_READY"} \
|
||||
{"m_sync_valid" "SYNC_VALID"} \
|
||||
{"m_sync" "SYNC_DATA"} \
|
||||
}
|
||||
adi_add_bus_clock "clk" "m_ctrl" "resetn"
|
||||
|
||||
foreach prefix [list "s0" "s1"] {
|
||||
adi_add_bus [format "%s_ctrl" $prefix] "slave" \
|
||||
"analog.com:interface:spi_engine_ctrl_rtl:1.0" \
|
||||
"analog.com:interface:spi_engine_ctrl:1.0" \
|
||||
[list \
|
||||
[list [format "%s_cmd_ready" $prefix] "CMD_READY"] \
|
||||
[list [format "%s_cmd_valid" $prefix] "CMD_VALID"] \
|
||||
[list [format "%s_cmd_data" $prefix] "CMD_DATA"] \
|
||||
[list [format "%s_sdo_ready" $prefix] "SDO_READY"] \
|
||||
[list [format "%s_sdo_valid" $prefix] "SDO_VALID"] \
|
||||
[list [format "%s_sdo_data" $prefix] "SDO_DATA"] \
|
||||
[list [format "%s_sdi_ready" $prefix] "SDI_READY"] \
|
||||
[list [format "%s_sdi_valid" $prefix] "SDI_VALID"] \
|
||||
[list [format "%s_sdi_data" $prefix] "SDI_DATA"] \
|
||||
[list [format "%s_sync_ready" $prefix] "SYNC_READY"] \
|
||||
[list [format "%s_sync_valid" $prefix] "SYNC_VALID"] \
|
||||
[list [format "%s_sync" $prefix] "SYNC_DATA"] \
|
||||
]
|
||||
adi_add_bus_clock "clk" [format "%s_ctrl" $prefix] "resetn"
|
||||
}
|
||||
|
||||
ipx::save_core [ipx::current_core]
|
|
@ -0,0 +1,42 @@
|
|||
####################################################################################
|
||||
####################################################################################
|
||||
## Copyright 2011(c) Analog Devices, Inc.
|
||||
## Auto-generated, do not modify!
|
||||
####################################################################################
|
||||
####################################################################################
|
||||
|
||||
M_DEPS := spi_engine_offload_ip.tcl
|
||||
M_DEPS += ../../scripts/adi_env.tcl
|
||||
M_DEPS += ../../scripts/adi_ip.tcl
|
||||
M_DEPS += spi_engine_offload.v
|
||||
|
||||
M_VIVADO := vivado -mode batch -source
|
||||
|
||||
M_FLIST := *.cache
|
||||
M_FLIST += *.data
|
||||
M_FLIST += *.xpr
|
||||
M_FLIST += *.log
|
||||
M_FLIST += component.xml
|
||||
M_FLIST += *.jou
|
||||
M_FLIST += xgui
|
||||
M_FLIST += .Xil
|
||||
|
||||
|
||||
|
||||
.PHONY: all clean clean-all
|
||||
all: spi_engine_offload.xpr
|
||||
|
||||
|
||||
clean:clean-all
|
||||
|
||||
|
||||
clean-all:
|
||||
rm -rf $(M_FLIST)
|
||||
|
||||
|
||||
spi_engine_offload.xpr: $(M_DEPS)
|
||||
rm -rf $(M_FLIST)
|
||||
$(M_VIVADO) spi_engine_offload_ip.tcl >> spi_engine_offload_ip.log 2>&1
|
||||
|
||||
####################################################################################
|
||||
####################################################################################
|
|
@ -0,0 +1,178 @@
|
|||
|
||||
module spi_engine_offload (
|
||||
input ctrl_clk,
|
||||
|
||||
input ctrl_cmd_wr_en,
|
||||
input [15:0] ctrl_cmd_wr_data,
|
||||
|
||||
input ctrl_sdo_wr_en,
|
||||
input [7:0] ctrl_sdo_wr_data,
|
||||
|
||||
input ctrl_enable,
|
||||
output ctrl_enabled,
|
||||
input ctrl_mem_reset,
|
||||
|
||||
input spi_clk,
|
||||
input spi_resetn,
|
||||
|
||||
input trigger,
|
||||
|
||||
output cmd_valid,
|
||||
input cmd_ready,
|
||||
output [15:0] cmd,
|
||||
|
||||
output sdo_data_valid,
|
||||
input sdo_data_ready,
|
||||
output [7:0] sdo_data,
|
||||
|
||||
input sdi_data_valid,
|
||||
output sdi_data_ready,
|
||||
input [7:0] sdi_data,
|
||||
|
||||
input sync_valid,
|
||||
output sync_ready,
|
||||
input [7:0] sync_data,
|
||||
|
||||
output offload_sdi_valid,
|
||||
input offload_sdi_ready,
|
||||
output [7:0] offload_sdi_data
|
||||
);
|
||||
|
||||
parameter SPI_CLK_ASYNC = 0;
|
||||
parameter CMD_MEM_ADDR_WIDTH = 4;
|
||||
parameter SDO_MEM_ADDR_WIDTH = 4;
|
||||
|
||||
reg spi_active = 1'b0;
|
||||
|
||||
reg [CMD_MEM_ADDR_WIDTH-1:0] ctrl_cmd_wr_addr = 'h00;
|
||||
reg [CMD_MEM_ADDR_WIDTH-1:0] spi_cmd_rd_addr = 'h00;
|
||||
reg [SDO_MEM_ADDR_WIDTH-1:0] ctrl_sdo_wr_addr = 'h00;
|
||||
reg [SDO_MEM_ADDR_WIDTH-1:0] spi_sdo_rd_addr = 'h00;
|
||||
|
||||
reg [15:0] cmd_mem[0:2**CMD_MEM_ADDR_WIDTH-1];
|
||||
reg [7:0] sdo_mem[0:2**SDO_MEM_ADDR_WIDTH-1];
|
||||
|
||||
wire [CMD_MEM_ADDR_WIDTH-1:0] spi_cmd_rd_addr_next;
|
||||
wire spi_enable;
|
||||
|
||||
assign cmd_valid = spi_active;
|
||||
assign sdo_data_valid = spi_active;
|
||||
assign sync_ready = 1'b1;
|
||||
|
||||
assign offload_sdi_valid = sdi_data_valid;
|
||||
assign sdi_data_ready = offload_sdi_ready;
|
||||
assign offload_sdi_data = sdi_data;
|
||||
|
||||
assign cmd = cmd_mem[spi_cmd_rd_addr];
|
||||
assign sdo_data = sdo_mem[spi_sdo_rd_addr];
|
||||
|
||||
generate if (SPI_CLK_ASYNC) begin
|
||||
|
||||
/*
|
||||
* The synchronization circuit takes care that there are no glitches on the
|
||||
* ctrl_enabled signal. ctrl_do_enable is asserted whenever ctrl_enable is
|
||||
* asserted, but only deasserted once the signal has been synchronized back from
|
||||
* the SPI domain. This makes sure that we can't end up in a state where the
|
||||
* enable signal in the SPI domain is asserted, but neither enable nor enabled
|
||||
* is asserted in the control domain.
|
||||
*/
|
||||
|
||||
reg ctrl_do_enable = 1'b0;
|
||||
wire ctrl_is_enabled;
|
||||
reg spi_enabled = 1'b0;
|
||||
|
||||
always @(posedge ctrl_clk) begin
|
||||
if (ctrl_enable == 1'b1) begin
|
||||
ctrl_do_enable <= 1'b1;
|
||||
end else if (ctrl_is_enabled == 1'b1) begin
|
||||
ctrl_do_enable <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
assign ctrl_enabled = ctrl_is_enabled | ctrl_do_enable;
|
||||
|
||||
always @(posedge spi_clk) begin
|
||||
spi_enabled <= spi_enable | spi_active;
|
||||
end
|
||||
|
||||
sync_bits # (
|
||||
.NUM_BITS(1),
|
||||
.CLK_ASYNC(1)
|
||||
) i_sync_enable (
|
||||
.in(ctrl_do_enable),
|
||||
.out_clk(spi_clk),
|
||||
.out_resetn(1'b1),
|
||||
.out(spi_enable)
|
||||
);
|
||||
|
||||
sync_bits # (
|
||||
.NUM_BITS(1),
|
||||
.CLK_ASYNC(1)
|
||||
) i_sync_enabled (
|
||||
.in(spi_enabled),
|
||||
.out_clk(ctrl_clk),
|
||||
.out_resetn(1'b1),
|
||||
.out(ctrl_is_enabled)
|
||||
);
|
||||
|
||||
end else begin
|
||||
assign spi_enable = ctrl_enable;
|
||||
assign ctrl_enabled = spi_enable | spi_active;
|
||||
end endgenerate
|
||||
|
||||
assign spi_cmd_rd_addr_next = spi_cmd_rd_addr + 1;
|
||||
|
||||
always @(posedge spi_clk) begin
|
||||
if (spi_resetn == 1'b0) begin
|
||||
spi_active <= 1'b0;
|
||||
end else begin
|
||||
if (spi_active == 1'b0) begin
|
||||
if (trigger == 1'b1 && spi_enable == 1'b1)
|
||||
spi_active <= 1'b1;
|
||||
end else if (cmd_ready == 1'b1 && spi_cmd_rd_addr_next == ctrl_cmd_wr_addr) begin
|
||||
spi_active <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge spi_clk) begin
|
||||
if (cmd_valid == 1'b0) begin
|
||||
spi_cmd_rd_addr <= 'h00;
|
||||
end else if (cmd_ready == 1'b1) begin
|
||||
spi_cmd_rd_addr <= spi_cmd_rd_addr_next;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge spi_clk) begin
|
||||
if (spi_active == 1'b0) begin
|
||||
spi_sdo_rd_addr <= 'h00;
|
||||
end else if (sdo_data_ready == 1'b1) begin
|
||||
spi_sdo_rd_addr <= spi_sdo_rd_addr + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge ctrl_clk) begin
|
||||
if (ctrl_mem_reset == 1'b1)
|
||||
ctrl_cmd_wr_addr <= 'h00;
|
||||
else if (ctrl_cmd_wr_en == 1'b1)
|
||||
ctrl_cmd_wr_addr <= ctrl_cmd_wr_addr + 1'b1;
|
||||
end
|
||||
|
||||
always @(posedge ctrl_clk) begin
|
||||
if (ctrl_cmd_wr_en == 1'b1)
|
||||
cmd_mem[ctrl_cmd_wr_addr] <= ctrl_cmd_wr_data;
|
||||
end
|
||||
|
||||
always @(posedge ctrl_clk) begin
|
||||
if (ctrl_mem_reset == 1'b1)
|
||||
ctrl_sdo_wr_addr <= 'h00;
|
||||
else if (ctrl_sdo_wr_en == 1'b1)
|
||||
ctrl_sdo_wr_addr <= ctrl_sdo_wr_addr + 1'b1;
|
||||
end
|
||||
|
||||
always @(posedge ctrl_clk) begin
|
||||
if (ctrl_sdo_wr_en == 1'b1)
|
||||
sdo_mem[ctrl_sdo_wr_addr] <= ctrl_sdo_wr_data;
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,56 @@
|
|||
source ../../scripts/adi_env.tcl
|
||||
source $ad_hdl_dir/library/scripts/adi_ip.tcl
|
||||
|
||||
adi_ip_create spi_engine_offload
|
||||
adi_ip_files spi_engine_offload [list \
|
||||
"spi_engine_offload.v" \
|
||||
]
|
||||
|
||||
adi_ip_properties_lite spi_engine_offload
|
||||
# Remove all inferred interfaces
|
||||
ipx::remove_all_bus_interface [ipx::current_core]
|
||||
|
||||
adi_add_bus "spi_engine_ctrl" "master" \
|
||||
"analog.com:interface:spi_engine_ctrl_rtl:1.0" \
|
||||
"analog.com:interface:spi_engine_ctrl:1.0" \
|
||||
{
|
||||
{"cmd_ready" "CMD_READY"} \
|
||||
{"cmd_valid" "CMD_VALID"} \
|
||||
{"cmd" "CMD_DATA"} \
|
||||
{"sdo_data_ready" "SDO_READY"} \
|
||||
{"sdo_data_valid" "SDO_VALID"} \
|
||||
{"sdo_data" "SDO_DATA"} \
|
||||
{"sdi_data_ready" "SDI_READY"} \
|
||||
{"sdi_data_valid" "SDI_VALID"} \
|
||||
{"sdi_data" "SDI_DATA"} \
|
||||
{"sync_ready" "SYNC_READY"} \
|
||||
{"sync_valid" "SYNC_VALID"} \
|
||||
{"sync_data" "SYNC_DATA"} \
|
||||
}
|
||||
|
||||
adi_add_bus "spi_engine_offload_ctrl" "slave" \
|
||||
"analog.com:interface:spi_engine_offload_ctrl_rtl:1.0" \
|
||||
"analog.com:interface:spi_engine_offload_ctrl:1.0" \
|
||||
{ \
|
||||
{ "ctrl_cmd_wr_en" "CMD_WR_EN"} \
|
||||
{ "ctrl_cmd_wr_data" "CMD_WR_DATA"} \
|
||||
{ "ctrl_sdo_wr_en" "SDO_WR_EN"} \
|
||||
{ "ctrl_sdo_wr_data" "SDO_WR_DATA"} \
|
||||
{ "ctrl_enable" "ENABLE"} \
|
||||
{ "ctrl_enabled" "ENABLED"} \
|
||||
{ "ctrl_mem_reset" "MEM_RESET"} \
|
||||
}
|
||||
|
||||
adi_add_bus "offload_sdi" "master" \
|
||||
"xilinx.com:interface:axis_rtl:1.0" \
|
||||
"xilinx.com:interface:axis:1.0" \
|
||||
{ \
|
||||
{"offload_sdi_valid" "TVALID"} \
|
||||
{"offload_sdi_ready" "TREADY"} \
|
||||
{"offload_sdi_data" "TDATA"} \
|
||||
}
|
||||
|
||||
adi_add_bus_clock "spi_clk" "spi_engine_ctrl:offload_sdi" "spi_resetn"
|
||||
adi_add_bus_clock "ctrl_clk" "spi_engine_offload_ctrl"
|
||||
|
||||
ipx::save_core [ipx::current_core]
|
Loading…
Reference in New Issue