blob: 3c4e9450398676e07fc4702d443b5bcdf2af1f31 [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
// SPDX-FileCopyrightText: 2021 , Dinesh Annayya
//
// 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
//
// http://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.
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileContributor: Created by Dinesh Annayya <dinesha@opencores.org>
//
//////////////////////////////////////////////////////////////////////
//// ////
//// LBIST CORE ////
//// ////
//// This file is part of the logic_bist project ////
//// https://github.com/dineshannayya/logic_bist.git ////
//// ////
//// Description ////
//// This block manages all the lbist sequence ////
//// ////
//// To Do: ////
//// nothing ////
//// ////
//// Author(s): ////
//// - Dinesh Annayya, dinesha@opencores.org ////
//// ////
//// Revision : ////
//// 0.1 - 29 Nov 2021 Dinesh A ////
//// Initial version ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2000 Authors and OPENCORES.ORG ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source 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. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
module lbist_core
#(parameter SCW = 8 // SCAN CHAIN WIDTH
)
(
input logic mclk,
input logic mclk_skew,
input logic rst_n,
input logic srst, // software reset
// Reg Bus Interface Signal
input logic lbist_start, // lbist start
input logic [15:0] cfg_lbist_pat, // Total Scan pattern to be run
input logic [15:0] cfg_chain_depth, // Scan Chain Depth
input logic cfg_lbist_rsb, // Option to bypass First scan shift compare
output logic lbist_done, // End of Ltest
output logic [31:0] lbist_sig, // scan signature
// Scan Control Signal
output logic scan_clk,
output logic scan_rst_n,
output logic scan_mode,
output logic scan_en,
output logic [SCW-1:0] scan_in,
input logic [SCW-1:0] scan_out
);
// FSM STATE
parameter FSM_IDLE = 4'b0000;
parameter FSM_RESET_WAIT = 4'b0001;
parameter FSM_IDLE_WAIT = 4'b0010;
parameter FSM_ASSERT_SCAN_EN = 4'b0011;
parameter FSM_SCAN_SHIFT = 4'b0100;
parameter FSM_DEASSERT_SCAN_EN = 4'b0101;
parameter FSM_DEASSERT_SCAN_CLK = 4'b0110;
parameter FSM_SCAN_CAPTURE = 4'b0111;
// Scan Sequence
// 1. scan_reset_n = 0, scan_clk_enb = 0, scan_en = 0, Wait 4 Cycle
// 2. scan_reset_n = 1, scan_clk_enb = 0, scan_en = 0, Wait 4 Cycle
// 3. scan_en = 1, Wait 4 Cycle
// 4. scan_clk_enb = 1 , Wait for Scan Depth, If Total Pattern over, Then Exit
// 5. scan_clk_enb = 0, scan_en = 0, Wait for 4 Cycle
// 6. scan_clk_en = 1 , Wait for 1 Cycle
// 7. scan_clk_en = 0 Go to #3
logic [3:0] state, next_state;
logic next_scan_en;
logic scan_clk_enb,next_scan_clk_enb;
logic [15:0]clk_cnt, next_clk_cnt;
logic next_scan_rst_n;
logic [15:0]scan_pat_cnt,next_scan_pat_cnt;
logic next_lbist_done;
logic lbist_start_d;
logic next_scan_mode;
logic r_sshift_done; // Indicate Reset Scan shift done, This is first pattern
always_ff @(negedge rst_n or posedge mclk_skew)
begin
if(rst_n == 1'b0) begin
state <= FSM_IDLE;
scan_en <= '0;
scan_clk_enb <= '0;
clk_cnt <= '0;
scan_rst_n <= '1;
scan_pat_cnt <= '0;
lbist_done <= '0;
lbist_start_d <= 0;
scan_mode <= 0;
r_sshift_done <= 0;
end else if(srst) begin
state <= FSM_IDLE;
scan_en <= '0;
scan_clk_enb <= '0;
clk_cnt <= '0;
scan_rst_n <= '1;
scan_pat_cnt <= '0;
lbist_done <= '0;
lbist_start_d <= 0;
scan_mode <= 0;
r_sshift_done <= 0;
end else begin
state <= next_state;
scan_en <= next_scan_en;
scan_clk_enb <= next_scan_clk_enb;
clk_cnt <= next_clk_cnt;
scan_rst_n <= next_scan_rst_n;
scan_pat_cnt <= next_scan_pat_cnt;
lbist_done <= next_lbist_done;
lbist_start_d <= lbist_start;
scan_mode <= next_scan_mode;
// After first scan capture, set reset scan shift done indication
if(state == FSM_SCAN_CAPTURE)
r_sshift_done <= 1;
end
end
wire lbist_pos_edge = (lbist_start_d ==0) && (lbist_start == 1);
always_comb begin
next_state = state;
next_scan_en = scan_en;
next_scan_clk_enb = scan_clk_enb;
next_clk_cnt = clk_cnt;
next_scan_rst_n = scan_rst_n;
next_scan_pat_cnt = scan_pat_cnt;
next_lbist_done = lbist_done;
next_scan_mode = scan_mode;
case(state)
FSM_IDLE:
if(lbist_pos_edge) begin
next_lbist_done = 0;
next_scan_pat_cnt = cfg_lbist_pat;
next_scan_mode = 1;
next_scan_rst_n = 0;
next_scan_en = 0;
next_scan_clk_enb = 0;
next_clk_cnt = 4;
next_state = FSM_RESET_WAIT;
end
FSM_RESET_WAIT:
if(clk_cnt == 0) begin
next_scan_rst_n = 1;
next_scan_en = 0;
next_clk_cnt = 4;
next_state = FSM_IDLE_WAIT;
end else begin
next_clk_cnt = next_clk_cnt - 1;
end
FSM_IDLE_WAIT:
if(clk_cnt == 0) begin
next_scan_en = 1;
next_clk_cnt = 4;
next_state = FSM_ASSERT_SCAN_EN;
end else begin
next_clk_cnt = next_clk_cnt - 1;
end
FSM_ASSERT_SCAN_EN:
if(clk_cnt == 0) begin
next_scan_clk_enb = 1;
next_clk_cnt = cfg_chain_depth;
next_state = FSM_SCAN_SHIFT;
end else begin
next_clk_cnt = next_clk_cnt - 1;
end
FSM_SCAN_SHIFT:
if(clk_cnt == 0) begin
if(scan_pat_cnt == 0) begin
next_lbist_done = 1;
next_scan_mode = 0;
next_state = FSM_IDLE ;
end else begin
next_scan_pat_cnt= next_scan_pat_cnt-1;
next_scan_clk_enb= 0;
next_clk_cnt = 1;
next_state = FSM_DEASSERT_SCAN_EN;
end
end else begin
next_clk_cnt = next_clk_cnt - 1;
end
FSM_DEASSERT_SCAN_EN:
if(clk_cnt == 0) begin
next_scan_en = 0;
next_clk_cnt = 4;
next_state = FSM_DEASSERT_SCAN_CLK;
end else begin
next_clk_cnt = next_clk_cnt - 1;
end
FSM_DEASSERT_SCAN_CLK:
if(clk_cnt == 0) begin
next_scan_clk_enb= 1;
next_scan_en = 0;
next_clk_cnt = 0;
next_state = FSM_SCAN_CAPTURE;
end else begin
next_clk_cnt = next_clk_cnt - 1;
end
FSM_SCAN_CAPTURE: begin
next_scan_clk_enb= 0;
next_scan_en = 0;
next_clk_cnt = 4;
next_state = FSM_IDLE_WAIT;
end
endcase
end
//--------------------------------
// Scan clock generation
//--------------------------------
clk_gate u_scan_gate (
.GCLK (scan_clk),
.TE (1'b0),
.EN (scan_clk_enb),
.CLK (mclk)
);
//--------------------------------
// Scan Pattern Generation
//--------------------------------
logic [31:0] tx_crc_out;
assign scan_in = (clk_cnt[1:0] == 2'b00) ? tx_crc_out[7:0] :
(clk_cnt[1:0] == 2'b01) ? tx_crc_out[15:8] :
(clk_cnt[1:0] == 2'b10) ? tx_crc_out[23:16] : tx_crc_out[31:24];
// Run CRC at SCAN SHIFT PHASE at every once in 4 cycles
wire crc_tx_run = (state == FSM_SCAN_SHIFT) & (clk_cnt[1:0] == 2'b11);
wire crc_rx_run = (cfg_lbist_rsb) ? r_sshift_done & (state == FSM_SCAN_SHIFT) & (clk_cnt[1:0] == 2'b11):
(state == FSM_SCAN_SHIFT) & (clk_cnt[1:0] == 2'b11);
wire crc_clear = lbist_pos_edge;
crc_32 u_tx_crc(
// List of outputs.
.crc_out (tx_crc_out),
// List of inputs
.run (crc_tx_run), // when asserted, crc is generated
.clear (crc_clear), // When asserted crc is re-initialized
.data_in (8'h0),
.mclk (mclk_skew),
.reset_n (rst_n)
);
crc_32 u_rx_crc(
// List of outputs.
.crc_out (lbist_sig),
// List of inputs
.run (crc_rx_run), // when asserted, crc is generated
.clear (crc_clear), // When asserted crc is re-initialized
.data_in (scan_out),
.mclk (mclk_skew),
.reset_n (rst_n)
);
endmodule