blob: 349f5a8deae072e299bc7d035458a49b97b23384 [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,
// 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;
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;
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;
reg [2:0] spi_s_state;
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 [15:0] rwaddr_r, wdata_r, wdata_latch_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;
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);
wire [10:0] test;
assign test = (data_count_max_r - 1) - dat_out_ctr;
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;
end else begin
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 <= (|adc_sel_o) & (wdata_rdy_r | (r_w_en_o & addr_rdy_r));
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) miso_o <= 1;
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
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
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)); // pos_edge &
end
always @(posedge mclk_i) begin
if (rst_i_r | neg_edge) dat_out_dn_latch <= 0;
else if (dat_out_dn_r) dat_out_dn_latch <= 1;
end
always @(posedge mclk_i) begin
if (rst_i_r | poll_dat_ctr_clr) poll_dat_ctr_r <= 0;
else begin
if (poll_ctr_en_w & mode_i) poll_dat_ctr_r <= poll_dat_ctr_r + 1;
end
end
always @(posedge mclk_i) begin
if (rst_i_r) dn_clr_o <= 0;
else begin
dn_clr_o <= ((!mode_i & dn_i) | (mode_i & poll_dn_i));
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
endmodule