first commit after restructuring

This commit is contained in:
2023-04-13 13:33:41 +08:00
commit 3c2cd0ba29
15090 changed files with 6794217 additions and 0 deletions
@@ -0,0 +1,456 @@
// ***************************************************************************
// ***************************************************************************
// Copyright 2014 - 2017 (c) Analog Devices, Inc. All rights reserved.
//
// In this HDL repository, there are many different and unique modules, consisting
// of various HDL (Verilog or VHDL) components. The individual modules are
// developed independently, and may be accompanied by separate and unique license
// terms.
//
// The user should read each of these license terms, and understand the
// freedoms and responsibilities that he or she has by using this source/core.
//
// This core is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.
//
// Redistribution and use of source or resulting binaries, with or without modification
// of this file, are permitted under one of the following two license terms:
//
// 1. The GNU General Public License version 2 as published by the
// Free Software Foundation, which can be found in the top level directory
// of this repository (LICENSE_GPL2), and also online at:
// <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
//
// OR
//
// 2. An ADI specific BSD license, which can be found in the top level directory
// of this repository (LICENSE_ADIBSD), and also on-line at:
// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD
// This will allow to generate bit files and not release the source code,
// as long as it attaches to an ADI device.
//
// ***************************************************************************
// ***************************************************************************
`timescale 1ns/100ps
module spi_engine_execution #(
parameter NUM_OF_CS = 1,
parameter DEFAULT_SPI_CFG = 0,
parameter DEFAULT_CLK_DIV = 0,
parameter DATA_WIDTH = 8, // Valid data widths values are 8/16/24/32
parameter NUM_OF_SDI = 1,
parameter [0:0] SDO_DEFAULT = 1'b0,
parameter [1:0] SDI_DELAY = 2'b00) (
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 [(DATA_WIDTH-1):0] sdo_data,
input sdi_data_ready,
output reg sdi_data_valid,
output [(NUM_OF_SDI * DATA_WIDTH)-1:0] sdi_data,
input sync_ready,
output reg sync_valid,
output [7:0] sync,
output reg sclk,
output reg sdo,
output reg sdo_t,
input [NUM_OF_SDI-1:0] sdi,
output reg [NUM_OF_CS-1:0] cs,
output reg three_wire
);
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 = 2'b00;
localparam REG_CONFIG = 2'b01;
localparam REG_WORD_LENGTH = 2'b10;
localparam BIT_COUNTER_WIDTH = DATA_WIDTH > 16 ? 5 :
DATA_WIDTH > 8 ? 4 : 3;
localparam BIT_COUNTER_CARRY = 2** (BIT_COUNTER_WIDTH + 1);
localparam BIT_COUNTER_CLEAR = {{8{1'b1}}, {BIT_COUNTER_WIDTH{1'b0}}, 1'b1};
reg sclk_int = 1'b0;
wire sdo_int_s;
reg sdo_t_int = 1'b0;
reg idle;
reg [7:0] clk_div_counter = 'h00;
reg [7:0] clk_div_counter_next = 'h00;
reg clk_div_last;
reg [(BIT_COUNTER_WIDTH+8):0] counter = 'h00;
wire [7:0] sleep_counter = counter[(BIT_COUNTER_WIDTH+8):(BIT_COUNTER_WIDTH+1)];
wire [1:0] cs_sleep_counter = counter[(BIT_COUNTER_WIDTH+2):(BIT_COUNTER_WIDTH+1)];
wire [2:0] cs_sleep_counter2 = counter[(BIT_COUNTER_WIDTH+3):(BIT_COUNTER_WIDTH+1)];
wire [(BIT_COUNTER_WIDTH-1):0] bit_counter = counter[BIT_COUNTER_WIDTH:1];
wire [7:0] transfer_counter = counter[(BIT_COUNTER_WIDTH+8):(BIT_COUNTER_WIDTH+1)];
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;
reg [7:0] word_length = DATA_WIDTH;
reg [7:0] left_aligned = 8'b0;
wire end_of_word;
reg [7:0] sdi_counter = 8'b0;
assign first_bit = ((bit_counter == 'h0) || (bit_counter == word_length));
assign last_bit = bit_counter == word_length - 1;
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;
reg sdo_enabled = 1'b0;
reg sdi_enabled = 1'b0;
reg [(DATA_WIDTH-1):0] data_sdo_shift = 'h0;
reg [SDI_DELAY+1:0] trigger_rx_d = {(SDI_DELAY+2){1'b0}};
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;
wire trigger_tx;
wire trigger_rx;
wire sleep_counter_compare;
wire cs_sleep_counter_compare;
wire cs_sleep_counter_compare2;
wire io_ready1;
wire io_ready2;
wire trigger_rx_s;
wire last_sdi_bit;
assign cmd_ready = idle;
always @(posedge clk) begin
if (exec_transfer_cmd) begin
sdo_enabled <= cmd[8];
sdi_enabled <= cmd[9];
end
end
always @(posedge clk) begin
if (cmd_ready & cmd_valid)
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
// Load the interface configurations from the 'Configuration Write'
// instruction
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;
word_length <= DATA_WIDTH;
left_aligned <= 8'b0;
end else if (exec_write_cmd == 1'b1) begin
if (cmd[9:8] == REG_CONFIG) begin
cpha <= cmd[0];
cpol <= cmd[1];
three_wire <= cmd[2];
end else if (cmd[9:8] == REG_CLK_DIV) begin
clk_div <= cmd[7:0];
end else if (cmd[9:8] == REG_WORD_LENGTH) begin
// the max value of this reg must be DATA_WIDTH
word_length <= cmd[7:0];
left_aligned <= DATA_WIDTH - 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
assign trigger_tx = trigger == 1'b1 && ntx_rx == 1'b0;
assign trigger_rx = trigger == 1'b1 && ntx_rx == 1'b1;
assign sleep_counter_compare = sleep_counter == cmd_d1[7:0] && clk_div_last == 1'b1;
assign cs_sleep_counter_compare = cs_sleep_counter == cmd_d1[9:8] && clk_div_last == 1'b1;
assign 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) begin
counter <= 'h00;
end else if (clk_div_last == 1'b1 && wait_for_io == 1'b0) begin
if (bit_counter == word_length) begin
counter <= (counter & BIT_COUNTER_CLEAR) + (transfer_active ? 'h1 : 'h10) + BIT_COUNTER_CARRY;
end else begin
counter <= counter + (transfer_active ? 'h1 : 'h10);
end
end
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_OF_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_sdi_bit == 1'b1 && trigger_rx_s == 1'b1)
sdi_data_valid <= 1'b1;
else if (sdi_data_ready == 1'b1)
sdi_data_valid <= 1'b0;
end
assign 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);
assign 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_int <= ~sdo_enabled;
end else begin
sdo_t_int <= 1'b1;
end
end
// Load the SDO parallel data into the SDO shift register. In case of a custom
// data width, additional bit shifting must done at load.
always @(posedge clk) begin
if ((inst_d1 == CMD_TRANSFER) && (!sdo_enabled)) begin
data_sdo_shift <= {DATA_WIDTH{SDO_DEFAULT}};
end else if (transfer_active == 1'b1 && trigger_tx == 1'b1) begin
if (first_bit == 1'b1)
data_sdo_shift <= sdo_data << left_aligned;
else
data_sdo_shift <= {data_sdo_shift[(DATA_WIDTH-2):0], 1'b0};
end
end
assign sdo_int_s = data_sdo_shift[DATA_WIDTH-1];
// In case of an interface with high clock rate (SCLK > 50MHz), the latch of
// the SDI line can be delayed with 1, 2 or 3 SPI core clock cycle.
// Taking the fact that in high SCLK frequencies the pre-scaler most likely will
// be set to 0, to reduce the core clock's speed, this delay will mean that SDI will
// be latched at one of the next consecutive SCLK edge.
always @(posedge clk) begin
trigger_rx_d <= {trigger_rx_d, trigger_rx};
end
assign trigger_rx_s = trigger_rx_d[SDI_DELAY+1];
// Load the serial data into SDI shift register(s), then link it to the output
// register of the module
wire cs_active_s = (inst_d1 == CMD_CHIPSELECT) & ~(&cmd_d1[NUM_OF_CS-1:0]);
genvar i;
generate
for (i=0; i<NUM_OF_SDI; i=i+1) begin: g_sdi_shift_reg
reg [DATA_WIDTH-1:0] data_sdi_shift;
always @(posedge clk) begin
if (cs_active_s) begin
data_sdi_shift <= 0;
end else begin
if (trigger_rx_s == 1'b1) begin
data_sdi_shift <= {data_sdi_shift, sdi[i]};
end
end
end
assign sdi_data[i*DATA_WIDTH+:DATA_WIDTH] = data_sdi_shift;
end
endgenerate
assign last_sdi_bit = (sdi_counter == word_length-1);
always @(posedge clk) begin
if (resetn == 1'b0) begin
sdi_counter <= 8'b0;
end else begin
if (trigger_rx_s == 1'b1) begin
sdi_counter <= last_sdi_bit ? 8'b0 : sdi_counter + 1'b1;
end
end
end
always @(posedge clk) begin
if (transfer_active == 1'b1) begin
sclk_int <= cpol ^ cpha ^ ntx_rx;
end else begin
sclk_int <= cpol;
end
end
// Additional register stage to improve timing
always @(posedge clk) begin
sclk <= sclk_int;
sdo <= sdo_int_s;
sdo_t <= sdo_t_int;
end
endmodule