blob: 35093e953b8e24ec211171e1482b3d8e2932bfc7 [file] [log] [blame]
// Copyright 2023 The Pigweed Authors
//
// 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
//
// https://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.
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////
module spi_s_core (
//
input [23:0] vbus_1,
input [23:0] vshunt_1,
input [23:0] vbus_2,
input [23:0] vshunt_2,
input [23:0] vbus_3,
input [23:0] vshunt_3,
input [23:0] vbus_4,
input [23:0] vshunt_4,
input [23:0] vbus_5,
input [23:0] vshunt_5,
input [23:0] vbus_6,
input [23:0] vshunt_6,
input [23:0] vbus_7,
input [23:0] vshunt_7,
input [23:0] vbus_8,
input [23:0] vshunt_8,
input [23:0] vbus_9,
input [23:0] vshunt_9,
input [23:0] vbus_10,
input [23:0] vshunt_10,
input [23:0] vbus_11,
input [23:0] vshunt_11,
//
input dn_i,
input poll_dn_i,
input [39:0] rdata_i,
output reg dn_clr_o,
output reg en_o,
output reg r_w_en_o,
output reg [5:0] rwaddr_o,
output reg [15:0] wdata_o,
output reg [10:0] adc_sel_o,
output [10:0] poll_adc_en_o,
// sys
input mclk_i,
input rst_i,
input mode_i,
output data_valid_o,
// spi
input sclk_i,
input mosi_i,
input cs_i,
output reg miso_o
);
localparam IDLE = 1;
localparam WT = 2;
localparam DN = 4;
localparam S0 = 1;
localparam S1 = 2;
localparam S2 = 4;
reg
sclk_i_r0,
sclk_i_r1,
sclk_i_r2,
cs_i_r0,
cs_i_r1,
cs_i_r2,
mosi_i_r0,
mosi_i_r1,
mosi_i_r2,
dat_out_dn_r,
rst_i_r,
wr_dn_valid_r,
poll_adc_sel_valid_r;
reg
spi_rdy_r,
dat_out_dn_latch,
dat_out_en_r,
dat_out_ctr_clr,
poll_dat_ctr_clr,
addr_rdy_r,
wdata_rdy_r,
dat_out_ctr_clr_r,
poll_ctr_en_r,
poll_ctr_en_r1,
addr_rdy_r1,
poll_adc_sel_en_r;
reg [2:0] spi_s_state, poll_adc_state, dat_out_dn_latch_ctr;
reg [3:0] adc_count, poll_dat_next_ctr_index_r; // Number of ADCs enabled for continous polling.
reg [4:0] i;
reg [5:0] rwaddr_latch_r, poll_dat_ctr_r;
reg [6:0] dat_in_ctr_r, data_count_max_r, dat_out_ctr;
reg [10:0] poll_adc_sel_r;
reg [15:0] rwaddr_r, wdata_r, wdata_latch_r, poll_dat_bits_ctr_r;
reg [23:0] poll_dat_r;
reg [39:0] dat_in_r, dat_out_r, dat_in_r1;
wire pos_edge, neg_edge, poll_ctr_en_w;
reg [4:0] poll_dat_next_ctr_r[11:0]; // Holds the index of valid ADCs for continous polling.
assign pos_edge = (sclk_i_r1 & !sclk_i_r2);
assign neg_edge = (!sclk_i_r1 & sclk_i_r2);
assign poll_ctr_en_w = dat_out_ctr_clr_r & dat_out_ctr_clr;
assign data_valid_o = (dat_out_en_r | wr_dn_valid_r);
assign poll_adc_en_o = poll_adc_sel_r;
always @(posedge mclk_i) begin
rst_i_r <= rst_i;
end
always @(posedge mclk_i) begin
if (rst_i_r) begin
{sclk_i_r0, sclk_i_r1, sclk_i_r2} <= 0;
{cs_i_r0, cs_i_r1, cs_i_r2} <= 3'b111;
{mosi_i_r0, mosi_i_r1, mosi_i_r2} <= 0;
end else begin
{sclk_i_r2, sclk_i_r1, sclk_i_r0} <= {sclk_i_r1, sclk_i_r0, sclk_i};
{cs_i_r0, cs_i_r1, cs_i_r2} <= {cs_i, cs_i_r0, cs_i_r1};
{mosi_i_r0, mosi_i_r1, mosi_i_r2} <= {mosi_i, mosi_i_r0, mosi_i_r1};
end
end
always @(posedge mclk_i) begin
if (rst_i_r) begin
dat_in_r <= 0;
dat_in_ctr_r <= 0;
end else begin
if (!cs_i_r2 & spi_rdy_r) begin
if (neg_edge) begin
dat_in_r <= {dat_in_r, mosi_i_r2};
dat_in_ctr_r <= dat_in_ctr_r + 1;
end
end else begin
dat_in_r <= 0;
dat_in_ctr_r <= 0;
end
end
end
always @(posedge mclk_i) begin
if (rst_i_r | mode_i) spi_rdy_r <= 0;
else begin
spi_rdy_r <= (spi_s_state == IDLE);
end
end
always @(posedge mclk_i) begin
if (rst_i_r) begin
addr_rdy_r <= 0;
addr_rdy_r1 <= 0; // Added to sync en_o with r_w_en_o
end else begin
addr_rdy_r1 <= addr_rdy_r;
if (dat_in_ctr_r == 24) // Changed from 16.
addr_rdy_r <= 1;
else addr_rdy_r <= 0;
end
end
always @(posedge mclk_i) begin
if (rst_i_r) begin
wdata_rdy_r <= 0;
end else begin
if (dat_in_ctr_r == 40) wdata_rdy_r <= 1;
else wdata_rdy_r <= 0;
end
end
always @(posedge mclk_i) begin
if (rst_i_r) begin
rwaddr_o <= 0;
r_w_en_o <= 0;
adc_sel_o <= 0;
end else begin
if (addr_rdy_r) begin
adc_sel_o <= dat_in_r1[17:7];
rwaddr_o <= dat_in_r1[6:1];
r_w_en_o <= dat_in_r1[0];
end
end
end
always @(posedge mclk_i) begin
if (rst_i_r) begin
dat_in_r1 <= 0;
end else begin
dat_in_r1 <= dat_in_r;
end
end
always @(posedge mclk_i) begin
if (rst_i_r) wdata_o <= 0;
else begin
if (wdata_rdy_r) wdata_o <= dat_in_r1;
end
end
always @(posedge mclk_i) begin
if (rst_i_r) en_o <= 0;
else begin
en_o <= ((!poll_adc_sel_en_r) & ((|adc_sel_o) & (wdata_rdy_r | (r_w_en_o & addr_rdy_r1)))); // Bit18 disables spi_s_state
end
end
always @(posedge mclk_i) begin
if (rst_i_r | mode_i) spi_s_state <= IDLE;
else begin
case (spi_s_state)
IDLE: begin
if (en_o) spi_s_state <= WT;
else spi_s_state <= IDLE;
// spi_s_state<=en_o?r_w_en_o?RD:WR:IDLE;
end
WT: begin
if (r_w_en_o) begin
if (dat_out_dn_latch) spi_s_state <= DN;
else spi_s_state <= WT;
end else begin
if (dn_i) spi_s_state <= DN;
else spi_s_state <= WT;
end
end
DN: begin
spi_s_state <= IDLE; // (pos_edge)?IDLE:DN;
end
default: spi_s_state <= IDLE;
endcase
end
end
always @(posedge mclk_i) begin
wr_dn_valid_r <= dn_i & ((~mode_i) & (~r_w_en_o));
poll_ctr_en_r <= poll_ctr_en_w;
poll_ctr_en_r1 <= poll_ctr_en_r;
end
always @(posedge mclk_i) begin
if (rst_i_r | dat_out_dn_latch) begin
dat_out_en_r <= 0;
end else begin
if ((mode_i & poll_dn_i) | ((!mode_i) & r_w_en_o & dn_i)) dat_out_en_r <= 1;
end
end
always @(posedge mclk_i) begin
if (rst_i_r) begin
miso_o <= 1;
end else begin
if (dat_out_en_r) begin
if (pos_edge) miso_o <= dat_out_r[((data_count_max_r-1)-dat_out_ctr)];
end else miso_o <= 1;
end
end
// Test only logic to verify total number of clock cycles. NC
// always @(posedge mclk_i) begin
// if (rst_i_r | poll_dat_bits_ctr_r == 528) poll_dat_bits_ctr_r <= 0;
// else begin
// if (mode_i & neg_edge) poll_dat_bits_ctr_r <= poll_dat_bits_ctr_r + 1;
// end
// end
always @(posedge mclk_i) begin
if (rst_i_r | dat_out_ctr_clr) dat_out_ctr <= 0;
else begin
if (dat_out_en_r) begin
if (neg_edge) dat_out_ctr <= dat_out_ctr + 1;
end else dat_out_ctr <= 0;
end
end
always @(posedge mclk_i) begin
if (rst_i_r) dat_out_r <= 0;
else begin
if (mode_i) begin
dat_out_r <= poll_dat_r;
end else begin
if (dn_i) dat_out_r <= rdata_i;
end
end
end
always @(posedge mclk_i) begin
case (poll_dat_ctr_r)
0: poll_dat_r <= vshunt_1;
1: poll_dat_r <= vbus_1;
2: poll_dat_r <= vshunt_2;
3: poll_dat_r <= vbus_2;
4: poll_dat_r <= vshunt_3;
5: poll_dat_r <= vbus_3;
6: poll_dat_r <= vshunt_4;
7: poll_dat_r <= vbus_4;
8: poll_dat_r <= vshunt_5;
9: poll_dat_r <= vbus_5;
10: poll_dat_r <= vshunt_6;
11: poll_dat_r <= vbus_6;
12: poll_dat_r <= vshunt_7;
13: poll_dat_r <= vbus_7;
14: poll_dat_r <= vshunt_8;
15: poll_dat_r <= vbus_8;
16: poll_dat_r <= vshunt_9;
17: poll_dat_r <= vbus_9;
18: poll_dat_r <= vshunt_10;
19: poll_dat_r <= vbus_10;
20: poll_dat_r <= vshunt_11;
21: poll_dat_r <= vbus_11;
default: poll_dat_r <= 0;
endcase
end
always @(posedge mclk_i) begin
if (rst_i_r) dn_clr_o <= 0;
else begin
// Changed from poll_dn_i -(Added multi-cycle path) for clear pulse.
dn_clr_o <= ((!mode_i & dn_i) | (mode_i & dat_out_dn_latch));
end
end
always @(posedge mclk_i) begin
if (rst_i_r) begin
data_count_max_r <= 16;
end else begin
if (mode_i) data_count_max_r <= 24;
else begin
if (r_w_en_o) begin
if (rwaddr_o == 4 || rwaddr_o == 5 || rwaddr_o == 7 || rwaddr_o == 8)
data_count_max_r <= 24;
else if (rwaddr_o == 9 || rwaddr_o == 10) data_count_max_r <= 40;
else data_count_max_r <= 16;
end else data_count_max_r <= 16;
end
end
end
always @(posedge mclk_i) begin
dat_out_ctr_clr <= (dat_out_ctr == data_count_max_r);
dat_out_ctr_clr_r <= dat_out_ctr_clr;
poll_dat_ctr_clr <= (poll_dat_ctr_r >= 22);
end
always @(posedge mclk_i) begin
if (rst_i_r) dat_out_dn_r <= 0;
else dat_out_dn_r <= (((!mode_i) & dat_out_ctr_clr) | (mode_i & poll_dat_ctr_clr));
end
always @(posedge mclk_i) begin
if (rst_i_r) dat_out_dn_latch_ctr <= 0;
dat_out_dn_latch_ctr <= (dat_out_dn_latch) ? dat_out_dn_latch_ctr + 1 : 0;
end
always @(posedge mclk_i) begin
if (rst_i_r | neg_edge | dat_out_dn_latch_ctr == 7) dat_out_dn_latch <= 0;
else if (dat_out_dn_r) dat_out_dn_latch <= 1;
end
// Logic for ADC selection for polling
always @(posedge mclk_i) begin
case (poll_adc_state)
S0: begin
poll_adc_state <= poll_adc_sel_valid_r ? S1 : S0;
adc_count <= 0;
i <= 0;
end
S1: begin
if (i < 12) begin
poll_dat_next_ctr_r[i] <= 11; // 5x11 queue
i <= i + 1;
end else begin
poll_adc_state <= S2;
i <= 0;
end
end
S2: begin
if (i < 11) begin
if (poll_adc_sel_r[i]) begin
adc_count <= adc_count + 1;
poll_dat_next_ctr_r[adc_count] <= i;
end
i <= i + 1;
end else poll_adc_state <= (poll_adc_sel_valid_r) ? S2 : S0;
end
default: poll_adc_state <= S0;
endcase
end
always @(posedge mclk_i) begin
if (rst_i_r) // TBD: Clear after completion of packet
poll_adc_sel_en_r <= 0;
else begin
if (addr_rdy_r) poll_adc_sel_en_r <= dat_in_r1[18];
end
end
always @(posedge mclk_i) begin
if (addr_rdy_r1 & poll_adc_sel_en_r) begin
poll_adc_sel_valid_r <= 1;
poll_adc_sel_r <= adc_sel_o; // Clear only with a write.
end else begin
poll_adc_sel_valid_r <= 0;
end
end
initial poll_adc_sel_r = 11'h07FF;
initial begin // POR Reset Value
for (i = 0; i < 12; i = i + 1) begin
poll_dat_next_ctr_r[i] = i;
end
end
always @(posedge mclk_i) begin
if (rst_i_r | poll_dat_ctr_clr) begin
poll_dat_ctr_r <= {poll_dat_next_ctr_r[0], 1'b0};
poll_dat_next_ctr_index_r <= 0;
end else begin
if (poll_ctr_en_w & mode_i) begin
if (!poll_dat_ctr_r[0]) begin
poll_dat_ctr_r <= poll_dat_ctr_r + 1;
poll_dat_next_ctr_index_r <= poll_dat_next_ctr_index_r + 1;
end else begin
poll_dat_ctr_r <= {poll_dat_next_ctr_r[poll_dat_next_ctr_index_r], 1'b0};
end
end
end
end
endmodule