1060 lines
36 KiB
Systemverilog
1060 lines
36 KiB
Systemverilog
|
// (C) 2001-2015 Altera Corporation. All rights reserved.
|
||
|
// Your use of Altera Corporation's design tools, logic functions and other
|
||
|
// software and tools, and its AMPP partner logic functions, and any output
|
||
|
// files any of the foregoing (including device programming or simulation
|
||
|
// files), and any associated documentation or information are expressly subject
|
||
|
// to the terms and conditions of the Altera Program License Subscription
|
||
|
// Agreement, Altera MegaCore Function License Agreement, or other applicable
|
||
|
// license agreement, including, without limitation, that your use is for the
|
||
|
// sole purpose of programming logic devices manufactured by Altera and sold by
|
||
|
// Altera or its authorized distributors. Please refer to the applicable
|
||
|
// agreement for further details.
|
||
|
|
||
|
|
||
|
// ******
|
||
|
// scc_mgr
|
||
|
// ******
|
||
|
//
|
||
|
// SCC Manager
|
||
|
//
|
||
|
// General Description
|
||
|
// -------------------
|
||
|
//
|
||
|
// This component allows the NIOS to control the delay chains in the IOs.
|
||
|
//
|
||
|
|
||
|
`timescale 1 ps / 1 ps
|
||
|
|
||
|
// altera message_off 10230
|
||
|
module sequencer_scc_mgr (
|
||
|
// Avalon Interface
|
||
|
|
||
|
avl_clk,
|
||
|
avl_reset_n,
|
||
|
avl_address,
|
||
|
avl_write,
|
||
|
avl_writedata,
|
||
|
avl_read,
|
||
|
avl_readdata,
|
||
|
avl_waitrequest,
|
||
|
|
||
|
scc_reset_n,
|
||
|
scc_clk,
|
||
|
scc_data,
|
||
|
scc_dqs_ena,
|
||
|
scc_dqs_io_ena,
|
||
|
scc_dq_ena,
|
||
|
scc_dm_ena,
|
||
|
scc_upd,
|
||
|
|
||
|
scc_sr_dqsenable_delayctrl,
|
||
|
scc_sr_dqsdisablen_delayctrl,
|
||
|
scc_sr_multirank_delayctrl,
|
||
|
|
||
|
capture_strobe_tracking,
|
||
|
afi_init_req,
|
||
|
afi_cal_req
|
||
|
);
|
||
|
|
||
|
parameter AVL_DATA_WIDTH = 32;
|
||
|
parameter AVL_ADDR_WIDTH = 13;
|
||
|
|
||
|
parameter MEM_IF_READ_DQS_WIDTH = 1;
|
||
|
parameter MEM_IF_WRITE_DQS_WIDTH = 1;
|
||
|
parameter MEM_IF_DQ_WIDTH = 36;
|
||
|
parameter MEM_IF_DM_WIDTH = 4;
|
||
|
parameter MEM_NUMBER_OF_RANKS = 1;
|
||
|
|
||
|
parameter DLL_DELAY_CHAIN_LENGTH = 8;
|
||
|
parameter FAMILY = "STRATIXIII";
|
||
|
parameter USE_2X_DLL = "false";
|
||
|
parameter USE_DQS_TRACKING = 0;
|
||
|
parameter USE_SHADOW_REGS = 0;
|
||
|
parameter DUAL_WRITE_CLOCK = 0;
|
||
|
|
||
|
parameter TRK_PARALLEL_SCC_LOAD = 0;
|
||
|
parameter SCC_DATA_WIDTH = 1;
|
||
|
|
||
|
localparam MAX_FAMILY_NAME_LEN = 30;
|
||
|
|
||
|
function integer get_dqs_sdata_bits(input [8*MAX_FAMILY_NAME_LEN-1:0] family);
|
||
|
if (family == "STRATIXV" || family == "ARRIAVGZ") return 101;
|
||
|
else if (family == "ARRIAV" || family == "CYCLONEV") return 30;
|
||
|
else return 46;
|
||
|
endfunction
|
||
|
|
||
|
function integer get_io_sdata_bits(input [8*MAX_FAMILY_NAME_LEN-1:0] family);
|
||
|
if (family == "STRATIXV" || family == "ARRIAVGZ") return 40;
|
||
|
else if (family == "ARRIAV" || family == "CYCLONEV") return 25;
|
||
|
else return 11;
|
||
|
endfunction
|
||
|
|
||
|
function integer get_datawidth(input [8*MAX_FAMILY_NAME_LEN-1:0] family);
|
||
|
if (family == "STRATIXV" || family == "ARRIAVGZ") return 42;
|
||
|
else if (family == "ARRIAV" || family == "CYCLONEV") return 19;
|
||
|
else return 24;
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
localparam DQS_IN_PHASE_MAX = 3;
|
||
|
localparam DQS_SDATA_BITS = get_dqs_sdata_bits(FAMILY);
|
||
|
localparam IO_SDATA_BITS = get_io_sdata_bits(FAMILY);
|
||
|
localparam DATAWIDTH = get_datawidth(FAMILY);
|
||
|
localparam RFILE_LATENCY = 3;
|
||
|
|
||
|
localparam MEM_DQ_PER_DQS = (MEM_IF_DQ_WIDTH / MEM_IF_WRITE_DQS_WIDTH);
|
||
|
localparam MEM_DM_PER_DQS = (MEM_IF_DM_WIDTH > MEM_IF_WRITE_DQS_WIDTH) ? (MEM_IF_DM_WIDTH / MEM_IF_WRITE_DQS_WIDTH) : 1;
|
||
|
localparam MEM_DQS_PER_DM = (MEM_IF_DM_WIDTH < MEM_IF_WRITE_DQS_WIDTH) ? (MEM_IF_WRITE_DQS_WIDTH / MEM_IF_DM_WIDTH) : 1;
|
||
|
|
||
|
localparam RFILE_DEPTH = log2(MEM_DQ_PER_DQS + 1 + MEM_DM_PER_DQS + MEM_IF_READ_DQS_WIDTH - 1) + 1;
|
||
|
localparam RFILE_ADDR_WIDTH = 6;
|
||
|
localparam RFILE_USED_DEPTH = (RFILE_DEPTH > RFILE_ADDR_WIDTH) ? RFILE_DEPTH : RFILE_ADDR_WIDTH;
|
||
|
|
||
|
localparam SCC_UPD_WIDTH = (USE_SHADOW_REGS == 1) ? MEM_IF_READ_DQS_WIDTH : 1;
|
||
|
localparam SAMPLE_COUNTER_WIDTH = 14;
|
||
|
|
||
|
typedef enum integer {
|
||
|
SCC_SCAN_DQS = 'b0000,
|
||
|
SCC_SCAN_DQS_IO = 'b0001,
|
||
|
SCC_SCAN_DQ_IO = 'b0010,
|
||
|
SCC_SCAN_DM_IO = 'b0011,
|
||
|
SCC_SCAN_UPD = 'b1000
|
||
|
} sdata_scan_t;
|
||
|
|
||
|
input avl_clk;
|
||
|
input avl_reset_n;
|
||
|
input [AVL_ADDR_WIDTH - 1:0] avl_address;
|
||
|
input avl_write;
|
||
|
input [AVL_DATA_WIDTH - 1:0] avl_writedata;
|
||
|
input avl_read;
|
||
|
output [AVL_DATA_WIDTH - 1:0] avl_readdata;
|
||
|
output avl_waitrequest;
|
||
|
|
||
|
input scc_clk;
|
||
|
input scc_reset_n;
|
||
|
output [SCC_DATA_WIDTH - 1:0] scc_data;
|
||
|
output [MEM_IF_READ_DQS_WIDTH - 1:0] scc_dqs_ena;
|
||
|
output [MEM_IF_READ_DQS_WIDTH - 1:0] scc_dqs_io_ena;
|
||
|
output [MEM_IF_DQ_WIDTH - 1:0] scc_dq_ena;
|
||
|
output [MEM_IF_DM_WIDTH - 1:0] scc_dm_ena;
|
||
|
output [SCC_UPD_WIDTH - 1:0] scc_upd;
|
||
|
|
||
|
output [7:0] scc_sr_dqsenable_delayctrl;
|
||
|
output [7:0] scc_sr_dqsdisablen_delayctrl;
|
||
|
output [7:0] scc_sr_multirank_delayctrl;
|
||
|
|
||
|
input [MEM_IF_READ_DQS_WIDTH - 1:0] capture_strobe_tracking;
|
||
|
input afi_init_req;
|
||
|
input afi_cal_req;
|
||
|
|
||
|
// internal versions of interfacing signals.
|
||
|
|
||
|
reg [AVL_DATA_WIDTH - 1:0] avl_readdata;
|
||
|
reg avl_waitrequest;
|
||
|
|
||
|
reg [SCC_DATA_WIDTH - 1:0] scc_data;
|
||
|
reg [MEM_IF_READ_DQS_WIDTH - 1:0] scc_dqs_ena;
|
||
|
reg [MEM_IF_READ_DQS_WIDTH - 1:0] scc_dqs_io_ena;
|
||
|
reg [MEM_IF_DQ_WIDTH - 1:0] scc_dq_ena;
|
||
|
reg [MEM_IF_DM_WIDTH - 1:0] scc_dm_ena;
|
||
|
reg [SCC_UPD_WIDTH - 1:0] scc_upd;
|
||
|
|
||
|
reg scc_data_c;
|
||
|
reg [MEM_IF_READ_DQS_WIDTH - 1:0] scc_dqs_ena_c;
|
||
|
reg [MEM_IF_READ_DQS_WIDTH - 1:0] scc_dqs_io_ena_c;
|
||
|
reg [MEM_IF_DQ_WIDTH - 1:0] scc_dq_ena_c;
|
||
|
reg [MEM_IF_DM_WIDTH - 1:0] scc_dm_ena_c;
|
||
|
reg [SCC_UPD_WIDTH - 1:0] scc_upd_c;
|
||
|
|
||
|
// IO config register
|
||
|
|
||
|
reg [IO_SDATA_BITS - 1:0] scc_io_cfg;
|
||
|
reg [IO_SDATA_BITS - 1:0] scc_io_cfg_curr;
|
||
|
reg [IO_SDATA_BITS - 1:0] scc_io_cfg_next;
|
||
|
|
||
|
// DQS config register
|
||
|
|
||
|
reg [DQS_SDATA_BITS - 1:0] scc_dqs_cfg;
|
||
|
reg [DQS_SDATA_BITS - 1:0] scc_dqs_cfg_curr;
|
||
|
reg [DQS_SDATA_BITS - 1:0] scc_dqs_cfg_next;
|
||
|
|
||
|
logic avl_cmd_parallel_scan;
|
||
|
logic [RFILE_ADDR_WIDTH-1:0] parallel_rfile_addr;
|
||
|
logic avl_par_read;
|
||
|
logic avl_load_done;
|
||
|
logic avl_load_done_r;
|
||
|
logic avl_cmd_par_end;
|
||
|
|
||
|
logic scc_load_done;
|
||
|
logic scc_load_done_r;
|
||
|
logic avl_par_read_r;
|
||
|
logic [RFILE_ADDR_WIDTH-1:0] parallel_group;
|
||
|
logic parallel_cfg_loaded;
|
||
|
logic [SCC_DATA_WIDTH - 1:0] scc_data_p;
|
||
|
logic [DQS_SDATA_BITS - 1:0] scc_dqs_cfg_curr_p [SCC_DATA_WIDTH - 1:0];
|
||
|
logic [DQS_SDATA_BITS - 1:0] scc_dqs_cfg_next_p [SCC_DATA_WIDTH - 1:0];
|
||
|
logic scc_parallel;
|
||
|
logic scc_parallel_r;
|
||
|
|
||
|
// is scc manager selected?
|
||
|
|
||
|
reg sel_scc;
|
||
|
|
||
|
// go signal going to the SCC clock side.
|
||
|
reg [3:0] scc_go_ena;
|
||
|
reg [3:0] scc_go_ena_r;
|
||
|
wire scc_go_group;
|
||
|
wire scc_go_io;
|
||
|
wire scc_go_update;
|
||
|
|
||
|
// enable pattern.
|
||
|
|
||
|
reg [7:0] scc_ena_addr;
|
||
|
reg [255:0] scc_ena_addr_decode;
|
||
|
|
||
|
// done signal coming back from the scc side.
|
||
|
|
||
|
reg scc_done;
|
||
|
|
||
|
// avalon version of scc done signal
|
||
|
|
||
|
reg avl_done;
|
||
|
|
||
|
// tracking signals
|
||
|
reg avl_cmd_trk_afi_end;
|
||
|
wire [AVL_DATA_WIDTH - 1:0] read_sample_counter;
|
||
|
|
||
|
// SCAN state machine
|
||
|
|
||
|
typedef enum int unsigned {
|
||
|
STATE_SCC_IDLE,
|
||
|
STATE_SCC_LOAD,
|
||
|
STATE_SCC_DONE
|
||
|
} STATE_SCC_RAM_T;
|
||
|
|
||
|
STATE_SCC_RAM_T scc_state_curr, scc_state_next;
|
||
|
reg [7:0] scc_shift_cnt_curr;
|
||
|
reg [7:0] scc_shift_cnt_next;
|
||
|
|
||
|
reg [DATAWIDTH-1:0] datain;
|
||
|
wire [DATAWIDTH-1:0] dataout_sr0;
|
||
|
wire [DATAWIDTH-1:0] dataout_sr1;
|
||
|
wire [DATAWIDTH-1:0] dataout;
|
||
|
wire [RFILE_ADDR_WIDTH-1:0] write_addr;
|
||
|
wire [RFILE_ADDR_WIDTH-1:0] read_addr;
|
||
|
reg [3:0] group;
|
||
|
wire write_en_sr0;
|
||
|
wire write_en_sr1;
|
||
|
|
||
|
reg [DATAWIDTH-1:0] scc_dataout;
|
||
|
|
||
|
reg [7:0] group_counter;
|
||
|
wire avl_cmd_group_counter;
|
||
|
wire [3:0] avl_cmd_section;
|
||
|
wire avl_cmd_rfile_group_not_io;
|
||
|
wire [RFILE_ADDR_WIDTH-1:0] avl_cmd_rfile_addr;
|
||
|
|
||
|
wire avl_cmd_rank;
|
||
|
reg [MEM_NUMBER_OF_RANKS - 1:0] avl_active_rank;
|
||
|
wire avl_active_shadow_reg;
|
||
|
|
||
|
wire avl_cmd_scan;
|
||
|
wire avl_cmd_scan_begin;
|
||
|
wire avl_cmd_scan_end;
|
||
|
wire [RFILE_ADDR_WIDTH-1:0] avl_cmd_scan_addr;
|
||
|
|
||
|
reg avl_doing_scan;
|
||
|
reg scc_doing_scan;
|
||
|
reg scc_doing_scan_r;
|
||
|
reg [7:0] scc_group_counter;
|
||
|
|
||
|
wire avl_cmd_rfile;
|
||
|
wire avl_cmd_rfile_begin;
|
||
|
wire avl_cmd_rfile_end;
|
||
|
reg [RFILE_LATENCY-1:0] avl_cmd_rfile_latency;
|
||
|
|
||
|
wire track_opr_check;
|
||
|
wire avl_cmd_counter_access;
|
||
|
|
||
|
wire avl_cmd_afi_req;
|
||
|
|
||
|
wire [AVL_DATA_WIDTH-1:0] shifted_dataout;
|
||
|
|
||
|
// metastability flops
|
||
|
reg avl_init_req_r;
|
||
|
reg avl_cal_req_r;
|
||
|
reg avl_init_req_r2;
|
||
|
reg avl_cal_req_r2;
|
||
|
reg avl_init_req_r3;
|
||
|
reg avl_cal_req_r3;
|
||
|
|
||
|
integer i,j,k,l;
|
||
|
|
||
|
assign sel_scc = 1'b1;
|
||
|
integer scan_offsets;
|
||
|
|
||
|
assign avl_cmd_section = avl_address[9:6];
|
||
|
assign avl_cmd_group_counter = (sel_scc && (avl_cmd_section == 4'b0000));
|
||
|
assign avl_cmd_rfile_group_not_io = ~(avl_address[9] == 1'b1 || avl_address[9:6] == 4'b0111) | (avl_address[9:6] == 4'b1010);
|
||
|
|
||
|
assign avl_cmd_rfile = (sel_scc && (avl_address[9:7] != 3'b111) && avl_cmd_section != 4'b0000 && avl_cmd_section != 4'hd);
|
||
|
assign avl_cmd_rfile_begin = (avl_read || avl_write) && (avl_cmd_rfile || avl_cmd_group_counter) && ~(|avl_cmd_rfile_latency);
|
||
|
assign avl_cmd_rfile_end = avl_cmd_rfile_latency[0];
|
||
|
assign avl_cmd_rfile_addr = {'0, (avl_cmd_rfile_group_not_io ? 0 : MEM_IF_READ_DQS_WIDTH) + avl_address[5:0]};
|
||
|
|
||
|
assign avl_cmd_rank = (sel_scc && avl_cmd_section == 4'he && avl_address[4] == 1'b1);
|
||
|
assign avl_cmd_parallel_scan = (avl_write && avl_cmd_section == 4'he && avl_address[10] == 1'b1);
|
||
|
|
||
|
assign avl_cmd_scan = (sel_scc && avl_cmd_section == 4'he && ~avl_cmd_rank && ~avl_cmd_parallel_scan);
|
||
|
assign avl_cmd_scan_begin = (avl_read || avl_write) && avl_cmd_scan && ~(avl_doing_scan) && ~(avl_done);
|
||
|
assign avl_cmd_scan_end = avl_doing_scan && avl_done;
|
||
|
assign avl_cmd_scan_addr = {'0, scan_offsets + ((avl_writedata[7:0] == 8'hFF) ? 0 : avl_writedata[5:0])};
|
||
|
|
||
|
always_comb begin
|
||
|
case(avl_address[1:0])
|
||
|
3: scan_offsets = (MEM_IF_READ_DQS_WIDTH + MEM_DQ_PER_DQS + 1);
|
||
|
2: scan_offsets = (MEM_IF_READ_DQS_WIDTH);
|
||
|
1: scan_offsets = (MEM_IF_READ_DQS_WIDTH + MEM_DQ_PER_DQS);
|
||
|
default: scan_offsets = '0;
|
||
|
endcase
|
||
|
end
|
||
|
|
||
|
assign track_opr_check = (avl_address[5:0] == 6'b111111) ? 1'b1 : 0;
|
||
|
assign avl_cmd_counter_access = sel_scc && avl_cmd_section == 4'hF && !track_opr_check;
|
||
|
assign avl_cmd_afi_req = (sel_scc && avl_cmd_section == 4'hd);
|
||
|
|
||
|
|
||
|
assign avl_waitrequest = (~avl_reset_n) || ((avl_read || avl_write) && ~avl_cmd_rfile_end && ~avl_cmd_scan_end && ~avl_cmd_trk_afi_end && ~avl_cmd_rank && ~avl_cmd_par_end);
|
||
|
always_comb begin
|
||
|
if (avl_cmd_rank) begin
|
||
|
avl_readdata[AVL_DATA_WIDTH - 1:MEM_NUMBER_OF_RANKS] = '0;
|
||
|
avl_readdata[MEM_NUMBER_OF_RANKS - 1:0] = avl_active_rank;
|
||
|
end else begin
|
||
|
if (avl_cmd_counter_access)
|
||
|
avl_readdata = read_sample_counter;
|
||
|
else
|
||
|
begin
|
||
|
if (avl_cmd_afi_req)
|
||
|
avl_readdata = {avl_cal_req_r3,avl_init_req_r3};
|
||
|
else
|
||
|
begin
|
||
|
if (avl_cmd_rfile)
|
||
|
avl_readdata = shifted_dataout;
|
||
|
else
|
||
|
avl_readdata = group_counter;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
// Assert that the SCC manager only receives broadcast or single bit scan requests for DQS and DM I/Os.
|
||
|
ERROR_DQS_IO_SCAN_WRONG_DATA:
|
||
|
assert property (@(posedge avl_clk) (avl_cmd_scan_begin && avl_address[3:0] == SCC_SCAN_DQS_IO) |-> (avl_writedata[7:0] == 8'hFF || avl_writedata[7:0] == 8'h00));
|
||
|
ERROR_DM_IO_SCAN_WRONG_DATA:
|
||
|
assert property (@(posedge avl_clk) (avl_cmd_scan_begin && avl_address[3:0] == SCC_SCAN_DM_IO) |-> (avl_writedata[7:0] == 8'hFF || avl_writedata[7:0] < MEM_DM_PER_DQS));
|
||
|
ERROR_DQS_SCAN_WRONG_DATA:
|
||
|
assert property (@(posedge avl_clk) (avl_cmd_scan_begin && avl_address[3:0] == SCC_SCAN_DQS) |-> (avl_writedata[7:0] == 8'hFF || avl_writedata[7:0] < MEM_IF_READ_DQS_WIDTH));
|
||
|
ERROR_DQ_IO_SCAN_WRONG_DATA:
|
||
|
assert property (@(posedge avl_clk) (avl_cmd_scan_begin && avl_address[3:0] == SCC_SCAN_DQ_IO) |-> (avl_writedata[7:0] == 8'hFF || avl_writedata[7:0] < MEM_DQ_PER_DQS));
|
||
|
|
||
|
|
||
|
typedef bit [13:0] t_setting_mask;
|
||
|
typedef bit [DATAWIDTH+1:0] t_setting_shifted_mask;
|
||
|
|
||
|
integer unsigned setting_offsets[1:12];
|
||
|
t_setting_shifted_mask setting_masks_lshift [1:12];
|
||
|
t_setting_mask setting_masks [1:12];
|
||
|
|
||
|
generate
|
||
|
if (FAMILY == "STRATIXV" || FAMILY == "ARRIAVGZ")
|
||
|
begin
|
||
|
assign setting_offsets[1] = 'd0;
|
||
|
assign setting_offsets[2] = 'd12;
|
||
|
assign setting_offsets[3] = 'd17;
|
||
|
assign setting_offsets[4] = 'd25;
|
||
|
assign setting_offsets[5] = 'd30;
|
||
|
assign setting_offsets[6] = 'd36;
|
||
|
assign setting_offsets[7] = 'd0;
|
||
|
assign setting_offsets[8] = 'd6;
|
||
|
assign setting_offsets[9] = 'd12;
|
||
|
assign setting_offsets[10] = 'd0;
|
||
|
assign setting_offsets[11] = 'd0;
|
||
|
assign setting_offsets[12] = 'd0;
|
||
|
|
||
|
assign setting_masks_lshift [1] = 'b0111111111111;
|
||
|
assign setting_masks_lshift [2] = 'b011111000000000000;
|
||
|
assign setting_masks_lshift [3] = 'b01111111100000000000000000;
|
||
|
assign setting_masks_lshift [4] = 'b0111110000000000000000000000000;
|
||
|
assign setting_masks_lshift [5] = 37'b0111111000000000000000000000000000000;
|
||
|
assign setting_masks_lshift [6] = 43'b0111111000000000000000000000000000000000000;
|
||
|
assign setting_masks_lshift [7] = 'b0111111;
|
||
|
assign setting_masks_lshift [8] = 'b0111111000000;
|
||
|
assign setting_masks_lshift [9] = 'b0111111111111000000000000;
|
||
|
assign setting_masks_lshift [10] = 'b0;
|
||
|
assign setting_masks_lshift [11] = 'b0;
|
||
|
assign setting_masks_lshift [12] = 'b0;
|
||
|
|
||
|
assign setting_masks [1] = 'b0111111111111;
|
||
|
assign setting_masks [2] = 'b011111;
|
||
|
assign setting_masks [3] = 'b011111111;
|
||
|
assign setting_masks [4] = 'b011111;
|
||
|
assign setting_masks [5] = 'b0111111;
|
||
|
assign setting_masks [6] = 'b0111111;
|
||
|
assign setting_masks [7] = 'b0111111;
|
||
|
assign setting_masks [8] = 'b0111111;
|
||
|
assign setting_masks [9] = 'b0111111111111;
|
||
|
assign setting_masks [10] = 'b0;
|
||
|
assign setting_masks [11] = 'b0;
|
||
|
assign setting_masks [12] = 'b0;
|
||
|
end
|
||
|
else if (FAMILY == "ARRIAV" || FAMILY == "CYCLONEV")
|
||
|
begin
|
||
|
assign setting_offsets[1] = 'd0;
|
||
|
assign setting_offsets[2] = 'd5;
|
||
|
assign setting_offsets[3] = 'd8;
|
||
|
assign setting_offsets[4] = 'd13;
|
||
|
assign setting_offsets[5] = 'd13;
|
||
|
assign setting_offsets[6] = 'd18;
|
||
|
assign setting_offsets[7] = 'd0;
|
||
|
assign setting_offsets[8] = 'd5;
|
||
|
assign setting_offsets[9] = 'd5;
|
||
|
assign setting_offsets[10] = 'd18;
|
||
|
assign setting_offsets[11] = 'd10;
|
||
|
assign setting_offsets[12] = 'd11;
|
||
|
|
||
|
assign setting_masks_lshift [1] = 'b011111;
|
||
|
assign setting_masks_lshift [2] = 'b011100000;
|
||
|
assign setting_masks_lshift [3] = 'b01111100000000;
|
||
|
assign setting_masks_lshift [4] = 'b0;
|
||
|
assign setting_masks_lshift [5] = 'b0111110000000000000;
|
||
|
assign setting_masks_lshift [6] = 'b0;
|
||
|
assign setting_masks_lshift [7] = 'b011111;
|
||
|
assign setting_masks_lshift [8] = 'b0;
|
||
|
assign setting_masks_lshift [9] = 'b01111100000;
|
||
|
assign setting_masks_lshift [10] = 'b01000000000000000000;
|
||
|
assign setting_masks_lshift [11] = 'b010000000000;
|
||
|
assign setting_masks_lshift [12] = 'b011100000000000;
|
||
|
|
||
|
assign setting_masks [1] = 'b011111;
|
||
|
assign setting_masks [2] = 'b0111;
|
||
|
assign setting_masks [3] = 'b011111;
|
||
|
assign setting_masks [4] = 'b0;
|
||
|
assign setting_masks [5] = 'b011111;
|
||
|
assign setting_masks [6] = 'b0;
|
||
|
assign setting_masks [7] = 'b011111;
|
||
|
assign setting_masks [8] = 'b0;
|
||
|
assign setting_masks [9] = 'b011111;
|
||
|
assign setting_masks [10] = 'b01;
|
||
|
assign setting_masks [11] = 'b01;
|
||
|
assign setting_masks [12] = 'b0111;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
assign setting_offsets[1] = 'd0;
|
||
|
assign setting_offsets[2] = 'd4;
|
||
|
assign setting_offsets[3] = 'd8;
|
||
|
assign setting_offsets[4] = 'd12;
|
||
|
assign setting_offsets[5] = 'd17;
|
||
|
assign setting_offsets[6] = 'd21;
|
||
|
assign setting_offsets[7] = 'd0;
|
||
|
assign setting_offsets[8] = 'd4;
|
||
|
assign setting_offsets[9] = 'd7;
|
||
|
assign setting_offsets[10] = 'd0;
|
||
|
assign setting_offsets[11] = 'd0;
|
||
|
assign setting_offsets[12] = 'd0;
|
||
|
|
||
|
assign setting_masks_lshift [1] = 'b01111;
|
||
|
assign setting_masks_lshift [2] = 'b011110000;
|
||
|
assign setting_masks_lshift [3] = 'b0111100000000;
|
||
|
assign setting_masks_lshift [4] = 'b11111000000000000;
|
||
|
assign setting_masks_lshift [5] = 'b0111100000000000000000;
|
||
|
assign setting_masks_lshift [6] = 'b00111000000000000000000000;
|
||
|
assign setting_masks_lshift [7] = 'b01111;
|
||
|
assign setting_masks_lshift [8] = 'b001110000;
|
||
|
assign setting_masks_lshift [9] = 'b011110000000;
|
||
|
assign setting_masks_lshift [10] = 'b0;
|
||
|
assign setting_masks_lshift [11] = 'b0;
|
||
|
assign setting_masks_lshift [12] = 'b0;
|
||
|
|
||
|
assign setting_masks [1] = 'b01111;
|
||
|
assign setting_masks [2] = 'b01111;
|
||
|
assign setting_masks [3] = 'b01111;
|
||
|
assign setting_masks [4] = 'b11111;
|
||
|
assign setting_masks [5] = 'b01111;
|
||
|
assign setting_masks [6] = 'b00111;
|
||
|
assign setting_masks [7] = 'b01111;
|
||
|
assign setting_masks [8] = 'b00111;
|
||
|
assign setting_masks [9] = 'b01111;
|
||
|
assign setting_masks [10] = 'b0;
|
||
|
assign setting_masks [11] = 'b0;
|
||
|
assign setting_masks [12] = 'b0;
|
||
|
end
|
||
|
endgenerate
|
||
|
|
||
|
always_ff @(posedge avl_clk or negedge avl_reset_n)
|
||
|
begin
|
||
|
if (~avl_reset_n)
|
||
|
begin
|
||
|
avl_active_rank <= '0;
|
||
|
end
|
||
|
else begin
|
||
|
if (avl_cmd_rank && avl_write) begin
|
||
|
avl_active_rank <= avl_writedata[MEM_NUMBER_OF_RANKS - 1:0];
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
always_ff @(posedge avl_clk or negedge avl_reset_n)
|
||
|
begin
|
||
|
if (~avl_reset_n)
|
||
|
begin
|
||
|
avl_cmd_rfile_latency <= 0;
|
||
|
avl_doing_scan <= 0;
|
||
|
end
|
||
|
else begin
|
||
|
avl_cmd_rfile_latency <= {avl_cmd_rfile_begin, avl_cmd_rfile_latency[RFILE_LATENCY - 1 : 1]};
|
||
|
avl_doing_scan <= (avl_cmd_scan_begin || avl_doing_scan) && ~avl_done;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
always_ff @(posedge avl_clk or negedge avl_reset_n)
|
||
|
begin
|
||
|
if (!avl_reset_n)
|
||
|
begin
|
||
|
avl_cmd_par_end <= 0;
|
||
|
parallel_rfile_addr <= 0;
|
||
|
avl_par_read <= 0;
|
||
|
avl_load_done <= 0;
|
||
|
avl_load_done_r <= 0;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
if (avl_cmd_parallel_scan && !avl_cmd_par_end && avl_done)
|
||
|
avl_cmd_par_end <= ~avl_cmd_par_end;
|
||
|
else
|
||
|
avl_cmd_par_end <= 0;
|
||
|
|
||
|
avl_load_done <= scc_load_done;
|
||
|
avl_load_done_r <= avl_load_done;
|
||
|
|
||
|
if (avl_cmd_parallel_scan)
|
||
|
begin
|
||
|
if (parallel_rfile_addr < SCC_DATA_WIDTH && avl_par_read && avl_load_done_r)
|
||
|
parallel_rfile_addr <= parallel_rfile_addr + 1'b1;
|
||
|
end
|
||
|
else
|
||
|
parallel_rfile_addr <= 0;
|
||
|
|
||
|
if (!avl_par_read)
|
||
|
begin
|
||
|
if (avl_cmd_parallel_scan && parallel_rfile_addr < SCC_DATA_WIDTH && !avl_load_done_r)
|
||
|
avl_par_read <= ~avl_par_read;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
if (avl_load_done_r)
|
||
|
avl_par_read <= ~avl_par_read;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
assign read_addr = avl_cmd_parallel_scan ? parallel_rfile_addr : (avl_cmd_scan ? avl_cmd_scan_addr : avl_cmd_rfile_addr);
|
||
|
assign write_addr = avl_cmd_rfile_addr;
|
||
|
|
||
|
assign datain = (dataout & (~setting_masks_lshift[avl_cmd_section])) | ((setting_masks[avl_cmd_section] & avl_writedata) << setting_offsets[avl_cmd_section]);
|
||
|
|
||
|
assign shifted_dataout = (dataout >> setting_offsets[avl_cmd_section]) & setting_masks[avl_cmd_section];
|
||
|
|
||
|
// config data storage
|
||
|
|
||
|
|
||
|
sequencer_scc_reg_file #(
|
||
|
.WIDTH (DATAWIDTH),
|
||
|
.DEPTH (RFILE_USED_DEPTH)
|
||
|
) sequencer_scc_reg_file_inst (
|
||
|
.clock (avl_clk ),
|
||
|
.data (datain ),
|
||
|
.rdaddress (read_addr ),
|
||
|
.wraddress (write_addr ),
|
||
|
.wren (write_en_sr0),
|
||
|
.q (dataout_sr0)
|
||
|
);
|
||
|
|
||
|
generate
|
||
|
if (USE_SHADOW_REGS == 1) begin
|
||
|
|
||
|
sequencer_scc_reg_file #(
|
||
|
.WIDTH (DATAWIDTH),
|
||
|
.DEPTH (RFILE_USED_DEPTH)
|
||
|
) sequencer_scc_reg_file_inst1 (
|
||
|
.clock (avl_clk ),
|
||
|
.data (datain ),
|
||
|
.rdaddress (read_addr ),
|
||
|
.wraddress (write_addr ),
|
||
|
.wren (write_en_sr1),
|
||
|
.q (dataout_sr1)
|
||
|
);
|
||
|
|
||
|
assign avl_active_shadow_reg = | avl_active_rank[MEM_NUMBER_OF_RANKS - 1 : MEM_NUMBER_OF_RANKS / 2];
|
||
|
|
||
|
assign write_en_sr0 = avl_cmd_rfile && avl_write && avl_cmd_rfile_latency[1] && (avl_active_shadow_reg == 1'b0);
|
||
|
assign write_en_sr1 = avl_cmd_rfile && avl_write && avl_cmd_rfile_latency[1] && (avl_active_shadow_reg == 1'b1);
|
||
|
assign dataout = (avl_active_shadow_reg == 1'b0 ? dataout_sr0 : dataout_sr1);
|
||
|
|
||
|
end else begin
|
||
|
assign write_en_sr0 = avl_cmd_rfile && avl_write && avl_cmd_rfile_latency[1];
|
||
|
assign dataout = dataout_sr0;
|
||
|
end
|
||
|
endgenerate
|
||
|
|
||
|
always_ff @(posedge avl_clk or negedge avl_reset_n)
|
||
|
begin
|
||
|
if (~avl_reset_n)
|
||
|
begin
|
||
|
group_counter <= '0;
|
||
|
end
|
||
|
else begin
|
||
|
if (avl_cmd_group_counter && avl_write)
|
||
|
begin
|
||
|
group_counter <= avl_writedata;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
always_ff @(posedge scc_clk or negedge scc_reset_n)
|
||
|
begin
|
||
|
if (~scc_reset_n)
|
||
|
begin
|
||
|
scc_dataout <= 0;
|
||
|
scc_doing_scan <= 0;
|
||
|
scc_doing_scan_r <= 0;
|
||
|
end
|
||
|
else begin
|
||
|
scc_dataout <= dataout;
|
||
|
scc_doing_scan <= avl_doing_scan;
|
||
|
scc_doing_scan_r <= scc_doing_scan || (avl_cmd_parallel_scan && parallel_cfg_loaded);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
// family specific decoder
|
||
|
generate
|
||
|
if (FAMILY == "STRATIXV" || FAMILY == "ARRIAVGZ")
|
||
|
begin
|
||
|
sequencer_scc_sv_wrapper # (
|
||
|
.DATAWIDTH (DATAWIDTH ),
|
||
|
.IO_SDATA_BITS (IO_SDATA_BITS ),
|
||
|
.DQS_SDATA_BITS (DQS_SDATA_BITS ),
|
||
|
.AVL_DATA_WIDTH (AVL_DATA_WIDTH ),
|
||
|
.DLL_DELAY_CHAIN_LENGTH (DLL_DELAY_CHAIN_LENGTH ),
|
||
|
.DUAL_WRITE_CLOCK (DUAL_WRITE_CLOCK)
|
||
|
) sequencer_scc_family_wrapper (
|
||
|
.reset_n_scc_clk (scc_reset_n ),
|
||
|
.scc_clk (scc_clk ),
|
||
|
.scc_dataout (scc_dataout ),
|
||
|
.scc_io_cfg (scc_io_cfg ),
|
||
|
.scc_dqs_cfg (scc_dqs_cfg ),
|
||
|
.scc_sr_dqsenable_delayctrl (scc_sr_dqsenable_delayctrl ),
|
||
|
.scc_sr_dqsdisablen_delayctrl (scc_sr_dqsdisablen_delayctrl ),
|
||
|
.scc_sr_multirank_delayctrl (scc_sr_multirank_delayctrl )
|
||
|
);
|
||
|
end
|
||
|
else if (FAMILY == "ARRIAV" || FAMILY == "CYCLONEV")
|
||
|
begin
|
||
|
assign scc_sr_dqsenable_delayctrl = '0;
|
||
|
assign scc_sr_dqsdisablen_delayctrl = '0;
|
||
|
assign scc_sr_multirank_delayctrl = '0;
|
||
|
|
||
|
sequencer_scc_acv_wrapper # (
|
||
|
.DATAWIDTH (DATAWIDTH ),
|
||
|
.IO_SDATA_BITS (IO_SDATA_BITS ),
|
||
|
.DQS_SDATA_BITS (DQS_SDATA_BITS ),
|
||
|
.AVL_DATA_WIDTH (AVL_DATA_WIDTH ),
|
||
|
.DLL_DELAY_CHAIN_LENGTH (DLL_DELAY_CHAIN_LENGTH ),
|
||
|
.USE_2X_DLL (USE_2X_DLL)
|
||
|
) sequencer_scc_family_wrapper (
|
||
|
.reset_n_scc_clk (scc_reset_n ),
|
||
|
.scc_clk (scc_clk ),
|
||
|
.scc_dataout (scc_dataout ),
|
||
|
.scc_io_cfg (scc_io_cfg ),
|
||
|
.scc_dqs_cfg (scc_dqs_cfg )
|
||
|
);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
|
||
|
assign scc_sr_dqsenable_delayctrl = '0;
|
||
|
assign scc_sr_dqsdisablen_delayctrl = '0;
|
||
|
assign scc_sr_multirank_delayctrl = '0;
|
||
|
|
||
|
sequencer_scc_siii_wrapper # (
|
||
|
.DATAWIDTH (DATAWIDTH ),
|
||
|
.IO_SDATA_BITS (IO_SDATA_BITS ),
|
||
|
.DQS_SDATA_BITS (DQS_SDATA_BITS ),
|
||
|
.AVL_DATA_WIDTH (AVL_DATA_WIDTH ),
|
||
|
.DLL_DELAY_CHAIN_LENGTH (DLL_DELAY_CHAIN_LENGTH )
|
||
|
) sequencer_scc_family_wrapper (
|
||
|
.reset_n_scc_clk (scc_reset_n ),
|
||
|
.scc_clk (scc_clk ),
|
||
|
.scc_dataout (scc_dataout ),
|
||
|
.scc_io_cfg (scc_io_cfg ),
|
||
|
.scc_dqs_cfg (scc_dqs_cfg )
|
||
|
);
|
||
|
end
|
||
|
endgenerate
|
||
|
|
||
|
// data transfer from SCC to AVALON
|
||
|
|
||
|
always_ff @ (posedge avl_clk) begin
|
||
|
avl_done <= scc_done;
|
||
|
end
|
||
|
|
||
|
// scan chain side state update
|
||
|
// scan chain state machine transitions.
|
||
|
|
||
|
always_ff @ (posedge scc_clk or negedge scc_reset_n) begin
|
||
|
if (~scc_reset_n) begin
|
||
|
scc_go_ena <= '0;
|
||
|
scc_go_ena_r <= '0;
|
||
|
scc_ena_addr <= '0;
|
||
|
scc_io_cfg_curr <= '0;
|
||
|
scc_dqs_cfg_curr <= '0;
|
||
|
scc_shift_cnt_curr <= '0;
|
||
|
scc_state_curr <= STATE_SCC_IDLE;
|
||
|
scc_group_counter <= '0;
|
||
|
for (k=0; k<SCC_DATA_WIDTH; k=k+1)
|
||
|
scc_dqs_cfg_curr_p[k] <= '0;
|
||
|
end
|
||
|
else begin
|
||
|
scc_go_ena <= avl_address[3:0];
|
||
|
scc_go_ena_r <= scc_go_ena;
|
||
|
scc_ena_addr <= avl_writedata[7:0];
|
||
|
scc_io_cfg_curr <= scc_io_cfg_next;
|
||
|
scc_dqs_cfg_curr <= scc_dqs_cfg_next;
|
||
|
scc_shift_cnt_curr <= scc_shift_cnt_next;
|
||
|
scc_state_curr <= scc_state_next;
|
||
|
scc_group_counter <= group_counter;
|
||
|
if (scc_load_done && !scc_load_done_r)
|
||
|
scc_dqs_cfg_curr_p[parallel_group] <= scc_dqs_cfg;
|
||
|
else if (scc_state_curr == STATE_SCC_LOAD)
|
||
|
begin
|
||
|
for (k=0; k<SCC_DATA_WIDTH; k=k+1)
|
||
|
scc_dqs_cfg_curr_p[k] <= scc_dqs_cfg_next_p[k];
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
assign scc_go_group = (scc_go_ena_r == SCC_SCAN_DQS);
|
||
|
assign scc_go_io = (scc_go_ena_r == SCC_SCAN_DQS_IO) || (scc_go_ena_r == SCC_SCAN_DQ_IO) || (scc_go_ena_r == SCC_SCAN_DM_IO);
|
||
|
assign scc_go_update = (scc_go_ena_r == SCC_SCAN_UPD);
|
||
|
|
||
|
always_ff @ (posedge scc_clk or negedge scc_reset_n)
|
||
|
begin
|
||
|
if (!scc_reset_n)
|
||
|
begin
|
||
|
avl_par_read_r <= 0;
|
||
|
scc_load_done <= 0;
|
||
|
scc_load_done_r <= 0;
|
||
|
parallel_group <= 0;
|
||
|
parallel_cfg_loaded <= 0;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
avl_par_read_r <= avl_par_read;
|
||
|
scc_load_done_r <= scc_load_done;
|
||
|
|
||
|
if (!parallel_cfg_loaded)
|
||
|
begin
|
||
|
if (!scc_load_done && scc_load_done_r)
|
||
|
begin
|
||
|
if (parallel_group == SCC_DATA_WIDTH-1)
|
||
|
parallel_cfg_loaded <= 1;
|
||
|
end
|
||
|
end
|
||
|
else
|
||
|
parallel_cfg_loaded <= 0;
|
||
|
|
||
|
if (!scc_load_done && scc_load_done_r)
|
||
|
begin
|
||
|
if (parallel_group < SCC_DATA_WIDTH-1)
|
||
|
parallel_group <= parallel_group + 1'b1;
|
||
|
else
|
||
|
parallel_group <= 0;
|
||
|
end
|
||
|
|
||
|
scc_load_done <= avl_par_read_r;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
always_ff @ (negedge scc_clk or negedge scc_reset_n)
|
||
|
begin
|
||
|
if (!scc_reset_n)
|
||
|
begin
|
||
|
scc_parallel <= 0;
|
||
|
scc_parallel_r <= 0;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
scc_parallel <= avl_cmd_parallel_scan;
|
||
|
scc_parallel_r <= scc_parallel;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
always_ff @ (negedge scc_clk) begin
|
||
|
if (scc_parallel_r)
|
||
|
scc_data <= scc_data_p;
|
||
|
else
|
||
|
for (l=0; l<SCC_DATA_WIDTH; l=l+1)
|
||
|
begin
|
||
|
scc_data[l] <= scc_data_c;
|
||
|
end
|
||
|
scc_dqs_ena <= scc_dqs_ena_c;
|
||
|
scc_dqs_io_ena <= scc_dqs_io_ena_c;
|
||
|
scc_dq_ena <= scc_dq_ena_c;
|
||
|
scc_dm_ena <= scc_dm_ena_c;
|
||
|
scc_upd <= scc_upd_c;
|
||
|
end
|
||
|
|
||
|
always_comb begin
|
||
|
scc_ena_addr_decode = '0;
|
||
|
|
||
|
if (scc_go_ena_r == SCC_SCAN_DQ_IO)
|
||
|
begin
|
||
|
if (scc_ena_addr == 8'b11111111)
|
||
|
scc_ena_addr_decode = {MEM_DQ_PER_DQS{1'b1}} << (scc_group_counter * MEM_DQ_PER_DQS);
|
||
|
else
|
||
|
scc_ena_addr_decode[scc_group_counter * MEM_DQ_PER_DQS + scc_ena_addr] = 1;
|
||
|
end
|
||
|
else if (scc_go_ena_r == SCC_SCAN_DQS) begin
|
||
|
if (scc_ena_addr == 8'b11111111)
|
||
|
scc_ena_addr_decode = '1;
|
||
|
else
|
||
|
scc_ena_addr_decode[scc_ena_addr] = 1;
|
||
|
end
|
||
|
else if (scc_go_ena_r == SCC_SCAN_DM_IO) begin
|
||
|
if (scc_ena_addr == 8'b11111111)
|
||
|
scc_ena_addr_decode = {MEM_DM_PER_DQS{1'b1}} << ((scc_group_counter * MEM_DM_PER_DQS) >> log2(MEM_DQS_PER_DM));
|
||
|
else
|
||
|
scc_ena_addr_decode[(scc_group_counter >> log2(MEM_DQS_PER_DM)) * MEM_DM_PER_DQS + scc_ena_addr] = 1;
|
||
|
end
|
||
|
else begin
|
||
|
if (scc_ena_addr == 8'b11111111)
|
||
|
scc_ena_addr_decode = '1;
|
||
|
else
|
||
|
scc_ena_addr_decode[scc_group_counter] = 1;
|
||
|
end
|
||
|
|
||
|
scc_state_next = scc_state_curr;
|
||
|
scc_shift_cnt_next = '0;
|
||
|
scc_io_cfg_next = scc_io_cfg;
|
||
|
scc_dqs_cfg_next = scc_dqs_cfg;
|
||
|
scc_data_c = 0;
|
||
|
scc_dqs_ena_c = '0;
|
||
|
scc_dqs_io_ena_c = '0;
|
||
|
scc_dq_ena_c = '0;
|
||
|
scc_dm_ena_c = '0;
|
||
|
scc_upd_c = '0;
|
||
|
scc_done = 0;
|
||
|
scc_data_p = '0;
|
||
|
for (j=0; j<SCC_DATA_WIDTH; j=j+1)
|
||
|
scc_dqs_cfg_next_p[j] = '0;
|
||
|
|
||
|
case (scc_state_curr)
|
||
|
STATE_SCC_IDLE: begin
|
||
|
if (scc_doing_scan_r) begin
|
||
|
if (scc_go_io) begin
|
||
|
scc_state_next = STATE_SCC_LOAD;
|
||
|
scc_shift_cnt_next = IO_SDATA_BITS - 1;
|
||
|
end else if (scc_go_group) begin
|
||
|
scc_state_next = STATE_SCC_LOAD;
|
||
|
scc_shift_cnt_next = DQS_SDATA_BITS - 1;
|
||
|
end else if (scc_go_update) begin
|
||
|
scc_state_next = STATE_SCC_DONE;
|
||
|
if (USE_SHADOW_REGS == 1) begin
|
||
|
if (scc_group_counter == 8'b11111111) begin
|
||
|
scc_upd_c = '1;
|
||
|
end else begin
|
||
|
scc_upd_c = '0;
|
||
|
scc_upd_c[scc_group_counter] = 1'b1;
|
||
|
end
|
||
|
end else begin
|
||
|
scc_upd_c = '1;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
STATE_SCC_LOAD: begin
|
||
|
scc_shift_cnt_next = scc_shift_cnt_curr - 1;
|
||
|
|
||
|
if (scc_go_group) begin
|
||
|
scc_dqs_ena_c = (scc_go_ena_r == SCC_SCAN_DQS) ? scc_ena_addr_decode : '0;
|
||
|
if (FAMILY == "STRATIXV" || FAMILY == "ARRIAVGZ" )
|
||
|
begin
|
||
|
scc_data_c = scc_dqs_cfg_curr[0];
|
||
|
scc_dqs_cfg_next = scc_dqs_cfg_curr >> 1;
|
||
|
|
||
|
for (j=0; j<SCC_DATA_WIDTH; j=j+1)
|
||
|
begin
|
||
|
scc_data_p[j] = scc_dqs_cfg_curr_p[j][0];
|
||
|
scc_dqs_cfg_next_p[j] = scc_dqs_cfg_curr_p[j] >> 1;
|
||
|
end
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
scc_data_c = scc_dqs_cfg_curr[DQS_SDATA_BITS - 1];
|
||
|
scc_dqs_cfg_next = scc_dqs_cfg_curr << 1;
|
||
|
|
||
|
for (j=0; j<SCC_DATA_WIDTH; j=j+1)
|
||
|
begin
|
||
|
scc_data_p[j] = scc_dqs_cfg_curr_p[j][DQS_SDATA_BITS - 1];
|
||
|
scc_dqs_cfg_next_p[j] = scc_dqs_cfg_curr_p[j] << 1;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if (scc_go_io) begin
|
||
|
scc_dqs_io_ena_c = (scc_go_ena_r == SCC_SCAN_DQS_IO) ? scc_ena_addr_decode : '0;
|
||
|
scc_dq_ena_c = (scc_go_ena_r == SCC_SCAN_DQ_IO) ? scc_ena_addr_decode : '0;
|
||
|
scc_dm_ena_c = (scc_go_ena_r == SCC_SCAN_DM_IO) ? scc_ena_addr_decode : '0;
|
||
|
if (FAMILY == "STRATIXV" || FAMILY == "ARRIAVGZ")
|
||
|
begin
|
||
|
scc_data_c = scc_io_cfg_curr[0];
|
||
|
scc_io_cfg_next = scc_io_cfg_curr >> 1;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
scc_data_c = scc_io_cfg_curr[IO_SDATA_BITS - 1];
|
||
|
scc_io_cfg_next = scc_io_cfg_curr << 1;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if (scc_shift_cnt_curr == 0) begin
|
||
|
scc_state_next = STATE_SCC_DONE;
|
||
|
end
|
||
|
end
|
||
|
STATE_SCC_DONE: begin
|
||
|
scc_done = 1;
|
||
|
|
||
|
if (~scc_doing_scan_r)
|
||
|
scc_state_next = STATE_SCC_IDLE;
|
||
|
end
|
||
|
default : begin end
|
||
|
endcase
|
||
|
end
|
||
|
|
||
|
always_ff @(posedge avl_clk, negedge avl_reset_n)
|
||
|
begin
|
||
|
if (~avl_reset_n)
|
||
|
avl_cmd_trk_afi_end <= 1'b0;
|
||
|
else
|
||
|
begin
|
||
|
if (sel_scc && (avl_cmd_section == 4'hF || avl_cmd_section == 4'hd) && (avl_write || avl_read) && ~avl_cmd_trk_afi_end)
|
||
|
avl_cmd_trk_afi_end <= 1'b1;
|
||
|
else
|
||
|
avl_cmd_trk_afi_end <= 1'b0;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
generate
|
||
|
wire avl_cmd_do_sample;
|
||
|
if (USE_DQS_TRACKING == 1)
|
||
|
begin
|
||
|
assign avl_cmd_do_sample = (avl_write && sel_scc && avl_cmd_section == 4'hF && track_opr_check && avl_cmd_trk_afi_end);
|
||
|
end
|
||
|
|
||
|
if (USE_DQS_TRACKING == 1)
|
||
|
begin
|
||
|
reg [MEM_IF_READ_DQS_WIDTH - 1:0] capture_strobe_tracking_r;
|
||
|
reg signed [SAMPLE_COUNTER_WIDTH - 1:0] sample_counter [MEM_IF_READ_DQS_WIDTH - 1:0];
|
||
|
assign read_sample_counter = {{(AVL_DATA_WIDTH-SAMPLE_COUNTER_WIDTH){sample_counter[avl_address[5:0]][SAMPLE_COUNTER_WIDTH - 1]}},sample_counter[avl_address[5:0]]};
|
||
|
|
||
|
always_ff @(posedge avl_clk, negedge avl_reset_n)
|
||
|
begin
|
||
|
if (~avl_reset_n)
|
||
|
capture_strobe_tracking_r <= 1'b0;
|
||
|
else
|
||
|
capture_strobe_tracking_r <= capture_strobe_tracking;
|
||
|
end
|
||
|
|
||
|
always_ff @(posedge avl_clk, negedge avl_reset_n)
|
||
|
begin
|
||
|
if (~avl_reset_n)
|
||
|
begin
|
||
|
for (i=0; i<MEM_IF_READ_DQS_WIDTH; i=i+1)
|
||
|
begin
|
||
|
sample_counter[i] <= 1'b0;
|
||
|
end
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
for (i=0; i<MEM_IF_READ_DQS_WIDTH; i=i+1)
|
||
|
begin
|
||
|
if (avl_cmd_counter_access && avl_write && i == avl_address[5:0])
|
||
|
sample_counter[i] <= avl_writedata;
|
||
|
else if (avl_cmd_do_sample && (i == avl_writedata[7:0] || avl_writedata[7:0] == 8'hFF))
|
||
|
begin
|
||
|
if (capture_strobe_tracking_r[i])
|
||
|
begin
|
||
|
if (!sample_counter[i][SAMPLE_COUNTER_WIDTH-1] && &sample_counter[i][SAMPLE_COUNTER_WIDTH-2:0])
|
||
|
sample_counter[i] <= sample_counter[i];
|
||
|
else
|
||
|
sample_counter[i] <= sample_counter[i] + 1'b1;
|
||
|
end
|
||
|
else if (!capture_strobe_tracking_r[i])
|
||
|
begin
|
||
|
if (sample_counter[i][SAMPLE_COUNTER_WIDTH-1] && ~(|sample_counter[i][SAMPLE_COUNTER_WIDTH-2:0]))
|
||
|
sample_counter[i] <= sample_counter[i];
|
||
|
else
|
||
|
sample_counter[i] <= sample_counter[i] - 1'b1;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
assign read_sample_counter = '0;
|
||
|
end
|
||
|
endgenerate
|
||
|
|
||
|
always_ff @(posedge avl_clk, negedge avl_reset_n)
|
||
|
begin
|
||
|
if (~avl_reset_n)
|
||
|
begin
|
||
|
avl_init_req_r <= 0;
|
||
|
avl_cal_req_r <= 0;
|
||
|
avl_init_req_r2 <= 0;
|
||
|
avl_cal_req_r2 <= 0;
|
||
|
avl_init_req_r3 <= 0;
|
||
|
avl_cal_req_r3 <= 0;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
avl_init_req_r <= afi_init_req;
|
||
|
avl_cal_req_r <= afi_cal_req;
|
||
|
avl_init_req_r2 <= avl_init_req_r;
|
||
|
avl_cal_req_r2 <= avl_cal_req_r;
|
||
|
|
||
|
if (avl_init_req_r2)
|
||
|
avl_init_req_r3 <= 1;
|
||
|
else
|
||
|
avl_init_req_r3 <= 0;
|
||
|
|
||
|
if (avl_cal_req_r2)
|
||
|
avl_cal_req_r3 <= 1;
|
||
|
else
|
||
|
avl_cal_req_r3 <= 0;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function integer log2;
|
||
|
input integer value;
|
||
|
begin
|
||
|
for (log2=0; value>0; log2=log2+1)
|
||
|
value = value>>1;
|
||
|
log2 = log2 - 1;
|
||
|
end
|
||
|
endfunction
|
||
|
|
||
|
endmodule
|