spi_engine: Update SPI Engine frame work

+ data width and number of SDI lines are configurable
+ axi_spi_engine module can have two different type of memory map interface (S_AXI or UP)
main
Istvan Csomortani 2015-12-14 15:57:54 +02:00
parent 29a0f27cd1
commit 4e57170384
4 changed files with 318 additions and 259 deletions

View File

@ -1,9 +1,9 @@
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,
@ -24,8 +24,20 @@ module axi_spi_engine (
output [ 1:0] s_axi_rresp,
output [31:0] s_axi_rdata,
output reg irq,
// up interface
input up_clk,
input up_rstn,
input up_wreq,
input [(UP_ADDRESS_WIDTH-1):0] up_waddr,
input [31:0] up_wdata,
output up_wack,
input up_rreq,
input [(UP_ADDRESS_WIDTH-1):0] up_raddr,
output [31:0] up_rdata,
output up_rack,
output reg irq,
// SPI signals
input spi_clk,
@ -38,11 +50,11 @@ module axi_spi_engine (
input sdo_data_ready,
output sdo_data_valid,
output [7:0] sdo_data,
output [(DATA_WIDTH-1):0] sdo_data,
output sdi_data_ready,
input sdi_data_valid,
input [(SDI_DATA_WIDTH-1):0] sdi_data,
input [(NUM_OF_SDI * DATA_WIDTH-1):0] sdi_data,
output sync_ready,
input sync_valid,
@ -53,7 +65,7 @@ module axi_spi_engine (
output [15:0] offload0_cmd_wr_data,
output offload0_sdo_wr_en,
output [7:0] offload0_sdo_wr_data,
output [(DATA_WIDTH-1):0] offload0_sdo_wr_data,
output reg offload0_mem_reset,
output reg offload0_enable,
@ -63,6 +75,8 @@ module axi_spi_engine (
parameter CMD_FIFO_ADDRESS_WIDTH = 4;
parameter SDO_FIFO_ADDRESS_WIDTH = 5;
parameter SDI_FIFO_ADDRESS_WIDTH = 5;
parameter MM_IF_TYPE = 0;
parameter UP_ADDRESS_WIDTH = 14;
parameter ASYNC_SPI_CLK = 0;
@ -72,9 +86,15 @@ parameter OFFLOAD0_CMD_MEM_ADDRESS_WIDTH = 4;
parameter OFFLOAD0_SDO_MEM_ADDRESS_WIDTH = 4;
parameter ID = 'h00;
parameter SDI_DATA_WIDTH = 8; // Valid data widths values are 8/16/24/32
parameter DATA_WIDTH = 8;
parameter NUM_OF_SDI = 1;
localparam PCORE_VERSION = 'h010071;
localparam S_AXI = 0;
localparam UP_FIFO = 1;
wire clk;
wire rstn;
wire [CMD_FIFO_ADDRESS_WIDTH:0] cmd_fifo_room;
wire cmd_fifo_almost_empty;
@ -86,28 +106,28 @@ 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 [(DATA_WIDTH-1):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 [31:0] sdi_fifo_out_data;
wire [(NUM_OF_SDI * DATA_WIDTH-1):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 up_sw_reset = 1'b1;
wire up_sw_resetn = ~up_sw_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;
reg [31:0] up_rdata_ff = 'd0;
reg up_wack_ff = 1'b0;
reg up_rack_ff = 1'b0;
wire up_wreq_s;
wire up_rreq_s;
wire [31:0] up_wdata_s;
wire [(UP_ADDRESS_WIDTH-1):0] up_waddr_s;
wire [(UP_ADDRESS_WIDTH-1):0] up_raddr_s;
// Scratch register
reg [31:0] up_scratch = 'h00;
@ -115,11 +135,20 @@ reg [31:0] up_scratch = 'h00;
reg [7:0] sync_id = 'h00;
reg sync_id_pending = 1'b0;
generate if (MM_IF_TYPE == S_AXI) begin
// assign clock and reset
assign clk = s_axi_aclk;
assign rstn = s_axi_aresetn;
// interface wrapper
up_axi #(
.ADDRESS_WIDTH (8)
.ADDRESS_WIDTH (UP_ADDRESS_WIDTH)
) i_up_axi (
.up_rstn(s_axi_aresetn),
.up_clk(s_axi_aclk),
.up_rstn(rstn),
.up_clk(clk),
.up_axi_awvalid(s_axi_awvalid),
.up_axi_awaddr(s_axi_awaddr),
.up_axi_awready(s_axi_awready),
@ -137,16 +166,44 @@ up_axi #(
.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)
.up_wreq(up_wreq_s),
.up_waddr(up_waddr_s),
.up_wdata(up_wdata_s),
.up_wack(up_wack_ff),
.up_rreq(up_rreq_s),
.up_raddr(up_raddr_s),
.up_rdata(up_rdata_ff),
.up_rack(up_rack_ff)
);
assign up_rdata = 32'b0;
assign up_rack = 1'b0;
assign up_wack = 1'b0;
end
endgenerate
generate if (MM_IF_TYPE == UP_FIFO) begin
// assign clock and reset
assign clk = up_clk;
assign rstn = up_rstn;
assign up_wreq_s = up_wreq;
assign up_waddr_s = up_waddr;
assign up_wdata_s = up_wdata;
assign up_wack = up_wack_ff;
assign up_rreq_s = up_rreq;
assign up_raddr_s = up_raddr;
assign up_rdata = up_rdata_ff;
assign up_rack = up_rack_ff;
end
endgenerate
// IRQ handling
reg [3:0] up_irq_mask = 'h0;
wire [3:0] up_irq_source;
@ -161,74 +218,74 @@ assign up_irq_source = {
assign up_irq_pending = up_irq_mask & up_irq_source;
always @(posedge s_axi_aclk) begin
if (s_axi_aresetn == 1'b0)
always @(posedge clk) begin
if (rstn == 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;
always @(posedge clk) begin
if (rstn == 1'b0) begin
up_wack_ff <= 1'b0;
up_scratch <= 'h00;
up_reset <= 1'b1;
up_sw_reset <= 1'b1;
up_irq_mask <= 'h00;
offload0_enable <= 1'b0;
offload0_mem_reset <= 1'b0;
end else begin
up_wack <= up_wreq;
up_wack_ff <= up_wreq_s;
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];
if (up_wreq_s) begin
case (up_waddr_s)
8'h02: up_scratch <= up_wdata_s;
8'h10: up_sw_reset <= up_wdata_s;
8'h20: up_irq_mask <= up_wdata_s;
8'h40: offload0_enable <= up_wdata_s[0];
8'h42: offload0_mem_reset <= up_wdata_s[0];
endcase
end
end
end
always @(posedge s_axi_aclk) begin
if (s_axi_aresetn == 1'b0) begin
up_rack <= 'd0;
always @(posedge clk) begin
if (rstn == 1'b0) begin
up_rack_ff <= 'd0;
end else begin
up_rack <= up_rreq;
up_rack_ff <= up_rreq_s;
end
end
always @(posedge s_axi_aclk) begin
case (up_raddr)
8'h00: up_rdata <= PCORE_VERSION;
8'h01: up_rdata <= 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;
always @(posedge clk) begin
case (up_raddr_s)
8'h00: up_rdata_ff <= PCORE_VERSION;
8'h01: up_rdata_ff <= ID;
8'h02: up_rdata_ff <= up_scratch;
8'h10: up_rdata_ff <= up_sw_reset;
8'h20: up_rdata_ff <= up_irq_mask;
8'h21: up_rdata_ff <= up_irq_pending;
8'h22: up_rdata_ff <= up_irq_source;
8'h30: up_rdata_ff <= sync_id;
8'h34: up_rdata_ff <= cmd_fifo_room;
8'h35: up_rdata_ff <= sdo_fifo_room;
8'h36: up_rdata_ff <= sdi_fifo_level;
8'h3a: up_rdata_ff <= sdi_fifo_out_data;
8'h3c: up_rdata_ff <= sdi_fifo_out_data; /* PEEK register */
8'h40: up_rdata_ff <= {offload0_enable};
8'h41: up_rdata_ff <= {offload0_enabled};
default: up_rdata_ff <= 'h00;
endcase
end
always @(posedge s_axi_aclk) begin
if (up_resetn == 1'b0) begin
always @(posedge clk) begin
if (up_sw_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
end else if (up_wreq_s == 1'b1 && up_waddr_s == 8'h21 && up_wdata_s[3] == 1'b1) begin
sync_id_pending <= 1'b0;
end
end
@ -240,13 +297,13 @@ generate if (ASYNC_SPI_CLK) begin
wire spi_reset;
ad_rst i_spi_resetn (
.preset(up_reset),
.preset(up_sw_reset),
.clk(spi_clk),
.rst(spi_reset)
);
assign spi_resetn = ~spi_reset;
end else begin
assign spi_resetn = ~up_reset;
assign spi_resetn = ~up_sw_reset;
end
endgenerate
@ -255,7 +312,7 @@ endgenerate
(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_in_data = up_wdata_s[15:0];
assign cmd_fifo_almost_empty =
`axi_spi_engine_check_watermark(cmd_fifo_room, CMD_FIFO_ADDRESS_WIDTH);
@ -265,8 +322,8 @@ util_axis_fifo #(
.ADDRESS_WIDTH(CMD_FIFO_ADDRESS_WIDTH),
.S_AXIS_REGISTERED(0)
) i_cmd_fifo (
.s_axis_aclk(s_axi_aclk),
.s_axis_aresetn(up_resetn),
.s_axis_aclk(clk),
.s_axis_aresetn(up_sw_resetn),
.s_axis_ready(cmd_fifo_in_ready),
.s_axis_valid(cmd_fifo_in_valid),
.s_axis_data(cmd_fifo_in_data),
@ -279,19 +336,19 @@ util_axis_fifo #(
.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_in_valid = up_wreq_s == 1'b1 && up_waddr_s == 8'h39;
assign sdo_fifo_in_data = up_wdata_s[(DATA_WIDTH-1):0];
assign sdo_fifo_almost_empty =
`axi_spi_engine_check_watermark(sdo_fifo_room, SDO_FIFO_ADDRESS_WIDTH);
util_axis_fifo #(
.DATA_WIDTH(8),
.DATA_WIDTH(DATA_WIDTH),
.ASYNC_CLK(ASYNC_SPI_CLK),
.ADDRESS_WIDTH(SDO_FIFO_ADDRESS_WIDTH),
.S_AXIS_REGISTERED(0)
) i_sdo_fifo (
.s_axis_aclk(s_axi_aclk),
.s_axis_aresetn(up_resetn),
.s_axis_aclk(clk),
.s_axis_aresetn(up_sw_resetn),
.s_axis_ready(sdo_fifo_in_ready),
.s_axis_valid(sdo_fifo_in_valid),
.s_axis_data(sdo_fifo_in_data),
@ -304,12 +361,12 @@ util_axis_fifo #(
.m_axis_data(sdo_data)
);
assign sdi_fifo_out_ready = up_rreq == 1'b1 && up_raddr == 8'h3a;
assign sdi_fifo_out_ready = up_rreq_s == 1'b1 && up_raddr_s == 8'h3a;
assign sdi_fifo_almost_full =
`axi_spi_engine_check_watermark(sdi_fifo_level, SDI_FIFO_ADDRESS_WIDTH);
util_axis_fifo #(
.DATA_WIDTH(SDI_DATA_WIDTH),
.DATA_WIDTH(NUM_OF_SDI * DATA_WIDTH),
.ASYNC_CLK(ASYNC_SPI_CLK),
.ADDRESS_WIDTH(SDI_FIFO_ADDRESS_WIDTH),
.S_AXIS_REGISTERED(0)
@ -320,18 +377,18 @@ util_axis_fifo #(
.s_axis_valid(sdi_data_valid),
.s_axis_data(sdi_data),
.m_axis_aclk(s_axi_aclk),
.m_axis_aresetn(up_resetn),
.m_axis_aclk(clk),
.m_axis_aresetn(up_sw_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_cmd_wr_en = up_wreq_s == 1'b1 && up_waddr_s == 8'h44;
assign offload0_cmd_wr_data = up_wdata_s[15:0];
assign offload0_sdo_wr_en = up_wreq == 1'b1 && up_waddr == 8'h45;
assign offload0_sdo_wr_data = up_wdata[7:0];
assign offload0_sdo_wr_en = up_wreq_s == 1'b1 && up_waddr_s == 8'h45;
assign offload0_sdo_wr_data = up_wdata_s[7:0];
endmodule

View File

@ -11,11 +11,12 @@ module spi_engine_execution (
input sdo_data_valid,
output reg sdo_data_ready,
input [7:0] sdo_data,
input [(DATA_WIDTH-1):0] sdo_data,
input sdi_data_ready,
output reg sdi_data_valid,
output [(SDI_DATA_WIDTH-1):0] sdi_data,
output [(NUM_OF_SDI * DATA_WIDTH-1):0] sdi_data,
input sync_ready,
output reg sync_valid,
@ -35,10 +36,9 @@ module spi_engine_execution (
parameter NUM_OF_CS = 1;
parameter DEFAULT_SPI_CFG = 0;
parameter DEFAULT_CLK_DIV = 0;
parameter SDI_DATA_WIDTH = 8; // Valid data widths values are 8/16/24/32
parameter DATA_WIDTH = 8; // Valid data widths values are 8/16/24/32
parameter NUM_OF_SDI = 1;
localparam NUM_OF_SDI = SDI_DATA_WIDTH >> 3;
localparam CMD_TRANSFER = 2'b00;
localparam CMD_CHIPSELECT = 2'b01;
localparam CMD_WRITE = 2'b10;
@ -88,10 +88,10 @@ 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;
reg [8:0] data_shift_1 = 'h0;
reg [8:0] data_shift_2 = 'h0;
reg [8:0] data_shift_3 = 'h0;
reg [(DATA_WIDTH):0] data_shift = 'h0;
reg [(DATA_WIDTH):0] data_shift_1 = 'h0;
reg [(DATA_WIDTH):0] data_shift_2 = 'h0;
reg [(DATA_WIDTH):0] data_shift_3 = 'h0;
wire [1:0] inst = cmd[13:12];
wire [1:0] inst_d1 = cmd_d1[13:12];
@ -296,20 +296,20 @@ 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;
data_shift[DATA_WIDTH:1] <= sdo_data;
else
data_shift[8:1] <= data_shift[7:0];
data_shift_1[8:1] <= data_shift_1[7:0];
data_shift_2[8:1] <= data_shift_2[7:0];
data_shift_3[8:1] <= data_shift_3[7:0];
data_shift[DATA_WIDTH:1] <= data_shift[(DATA_WIDTH-1):0];
data_shift_1[DATA_WIDTH:1] <= data_shift_1[(DATA_WIDTH-1):0];
data_shift_2[DATA_WIDTH:1] <= data_shift_2[(DATA_WIDTH-1):0];
data_shift_3[DATA_WIDTH:1] <= data_shift_3[(DATA_WIDTH-1):0];
end
end
assign sdo = data_shift[8];
assign sdi_data = (NUM_OF_SDI == 1) ? data_shift[7:0] :
(NUM_OF_SDI == 2) ? {data_shift_1[7:0], data_shift[7:0]} :
(NUM_OF_SDI == 3) ? {data_shift_2[7:0], data_shift_1[7:0], data_shift[7:0]} :
(NUM_OF_SDI == 4) ? {data_shift_3[7:0], data_shift_2[7:0], data_shift_1[7:0], data_shift[7:0]} :
assign sdo = data_shift[DATA_WIDTH];
assign sdi_data = (NUM_OF_SDI == 1) ? data_shift[(DATA_WIDTH-1):0] :
(NUM_OF_SDI == 2) ? {data_shift_1[(DATA_WIDTH-1):0], data_shift[(DATA_WIDTH-1):0]} :
(NUM_OF_SDI == 3) ? {data_shift_2[(DATA_WIDTH-1):0], data_shift_1[(DATA_WIDTH-1):0], data_shift[(DATA_WIDTH-1):0]} :
(NUM_OF_SDI == 4) ? {data_shift_3[(DATA_WIDTH-1):0], data_shift_2[(DATA_WIDTH-1):0], data_shift_1[(DATA_WIDTH-1):0], data_shift[(DATA_WIDTH-1):0]} :
data_shift[7:0];
always @(posedge clk) begin

View File

@ -10,11 +10,11 @@ module spi_engine_interconnect (
output m_sdo_valid,
input m_sdo_ready,
output [7:0] m_sdo_data,
output [(DATA_WIDTH-1):0] m_sdo_data,
input m_sdi_valid,
output m_sdi_ready,
input [(SDI_DATA_WIDTH-1):0] m_sdi_data,
input [(NUM_OF_SDI * DATA_WIDTH-1):0] m_sdi_data,
input m_sync_valid,
output m_sync_ready,
@ -27,11 +27,11 @@ module spi_engine_interconnect (
input s0_sdo_valid,
output s0_sdo_ready,
input [7:0] s0_sdo_data,
input [(DATA_WIDTH-1):0] s0_sdo_data,
output s0_sdi_valid,
input s0_sdi_ready,
output [(SDI_DATA_WIDTH-1):0] s0_sdi_data,
output [(NUM_OF_SDI * DATA_WIDTH-1):0] s0_sdi_data,
output s0_sync_valid,
input s0_sync_ready,
@ -44,18 +44,19 @@ module spi_engine_interconnect (
input s1_sdo_valid,
output s1_sdo_ready,
input [7:0] s1_sdo_data,
input [(DATA_WIDTH-1):0] s1_sdo_data,
output s1_sdi_valid,
input s1_sdi_ready,
output [(SDI_DATA_WIDTH-1):0] s1_sdi_data,
output [(NUM_OF_SDI * DATA_WIDTH-1):0] s1_sdi_data,
output s1_sync_valid,
input s1_sync_ready,
output [7:0] s1_sync
);
parameter SDI_DATA_WIDTH = 8; // Valid data widths values are 8/16/24/32
parameter DATA_WIDTH = 8; // Valid data widths values are 8/16/24/32
parameter NUM_OF_SDI = 1;
reg s_active = 1'b0;

View File

@ -6,7 +6,7 @@ module spi_engine_offload (
input [15:0] ctrl_cmd_wr_data,
input ctrl_sdo_wr_en,
input [7:0] ctrl_sdo_wr_data,
input [(DATA_WIDTH-1):0] ctrl_sdo_wr_data,
input ctrl_enable,
output ctrl_enabled,
@ -23,11 +23,11 @@ module spi_engine_offload (
output sdo_data_valid,
input sdo_data_ready,
output [7:0] sdo_data,
output [(DATA_WIDTH-1):0] sdo_data,
input sdi_data_valid,
output sdi_data_ready,
input [(SDI_DATA_WIDTH-1):0] sdi_data,
input [(NUM_OF_SDI * DATA_WIDTH-1):0] sdi_data,
input sync_valid,
output sync_ready,
@ -35,13 +35,14 @@ module spi_engine_offload (
output offload_sdi_valid,
input offload_sdi_ready,
output [(SDI_DATA_WIDTH-1):0] offload_sdi_data
output [(NUM_OF_SDI * DATA_WIDTH-1):0] offload_sdi_data
);
parameter ASYNC_SPI_CLK = 0;
parameter CMD_MEM_ADDRESS_WIDTH = 4;
parameter SDO_MEM_ADDRESS_WIDTH = 4;
parameter SDI_DATA_WIDTH = 8; // Valid data widths values are 8/16/24/32
parameter DATA_WIDTH = 8; // Valid data widths values are 8/16/24/32
parameter NUM_OF_SDI = 1;
reg spi_active = 1'b0;
@ -51,7 +52,7 @@ reg [SDO_MEM_ADDRESS_WIDTH-1:0] ctrl_sdo_wr_addr = 'h00;
reg [SDO_MEM_ADDRESS_WIDTH-1:0] spi_sdo_rd_addr = 'h00;
reg [15:0] cmd_mem[0:2**CMD_MEM_ADDRESS_WIDTH-1];
reg [7:0] sdo_mem[0:2**SDO_MEM_ADDRESS_WIDTH-1];
reg [(DATA_WIDTH-1):0] sdo_mem[0:2**SDO_MEM_ADDRESS_WIDTH-1];
wire [CMD_MEM_ADDRESS_WIDTH-1:0] spi_cmd_rd_addr_next;
wire spi_enable;