635 lines
26 KiB
Verilog
635 lines
26 KiB
Verilog
// (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.
|
|
|
|
|
|
// synopsys translate_off
|
|
`timescale 1 ns / 1 ns
|
|
// synopsys translate_on
|
|
|
|
module altera_jtag_streaming #(
|
|
parameter PURPOSE = 0,
|
|
parameter UPSTREAM_FIFO_SIZE = 0,
|
|
parameter DOWNSTREAM_FIFO_SIZE = 0,
|
|
parameter MGMT_CHANNEL_WIDTH = -1
|
|
) (
|
|
// JTAG Signals
|
|
input wire tck,
|
|
input wire tdi,
|
|
output reg tdo,
|
|
input wire [2:0] ir_in,
|
|
input wire virtual_state_cdr,
|
|
input wire virtual_state_sdr,
|
|
input wire virtual_state_udr,
|
|
|
|
input wire reset_n,
|
|
// Source Signals
|
|
output wire [7:0] source_data,
|
|
output wire source_valid,
|
|
// Sink Signals
|
|
input wire [7:0] sink_data,
|
|
input wire sink_valid,
|
|
output wire sink_ready,
|
|
// Clock Debug Signals
|
|
input wire clock_to_sample,
|
|
input wire reset_to_sample,
|
|
// Resetrequest signal
|
|
output reg resetrequest,
|
|
// Debug reset and management channel
|
|
output wire debug_reset,
|
|
output reg mgmt_valid,
|
|
output reg [(MGMT_CHANNEL_WIDTH>0?MGMT_CHANNEL_WIDTH:1)-1:0] mgmt_channel,
|
|
output reg mgmt_data
|
|
);
|
|
|
|
// function to calculate log2, floored.
|
|
function integer flog2;
|
|
input [31:0] Depth;
|
|
integer i;
|
|
begin
|
|
i = Depth;
|
|
if ( i <= 0 ) flog2 = 0;
|
|
else begin
|
|
for(flog2 = -1; i > 0; flog2 = flog2 + 1)
|
|
i = i >> 1;
|
|
end
|
|
end
|
|
endfunction // flog2
|
|
|
|
localparam UPSTREAM_ENCODED_SIZE = flog2(UPSTREAM_FIFO_SIZE);
|
|
localparam DOWNSTREAM_ENCODED_SIZE = flog2(DOWNSTREAM_FIFO_SIZE);
|
|
|
|
localparam TCK_TO_SYSCLK_SYNC_DEPTH = 8;
|
|
localparam SYSCLK_TO_TCK_SYNC_DEPTH = 3;
|
|
|
|
// IR values determine the operating modes
|
|
localparam DATA = 0;
|
|
localparam LOOPBACK = 1;
|
|
localparam DEBUG = 2;
|
|
localparam INFO = 3;
|
|
localparam CONTROL = 4;
|
|
localparam MGMT = 5;
|
|
|
|
// Operating Modes:
|
|
// Data - To send data which its size and valid position are encoded in the header bytes of the data stream
|
|
// Loopback - To become a JTAG loopback with a bypass register
|
|
// Debug - To read the values of the clock sensing, clock sampling and reset sampling
|
|
// Info - To read the parameterized values that describe the components connected to JTAG Phy which is of great interest to the driver
|
|
// Control - To set the offset of bit-padding and to do a reset request
|
|
// Mgmt - Send management commands (resets mostly) to agents
|
|
|
|
localparam IRWIDTH = 3;
|
|
|
|
// State machine encoding for write_state
|
|
localparam ST_BYPASS = 'h0;
|
|
localparam ST_HEADER_1 = 'h1;
|
|
localparam ST_HEADER_2 = 'h2;
|
|
localparam ST_WRITE_DATA = 'h3;
|
|
|
|
// State machine encoding for read_state
|
|
localparam ST_HEADER = 'h0;
|
|
localparam ST_PADDED = 'h1;
|
|
localparam ST_READ_DATA = 'h2;
|
|
|
|
reg [1:0] write_state = ST_BYPASS;
|
|
reg [1:0] read_state = ST_HEADER;
|
|
|
|
reg [ 7:0] dr_data_in = 'b0;
|
|
reg [ 7:0] dr_data_out = 'b0;
|
|
reg dr_loopback = 'b0;
|
|
reg [ 2:0] dr_debug = 'b0;
|
|
reg [10:0] dr_info = 'b0;
|
|
reg [ 8:0] dr_control = 'b0;
|
|
reg [MGMT_CHANNEL_WIDTH+2:0] dr_mgmt = 'b0;
|
|
|
|
reg [ 8:0] padded_bit_counter = 'b0;
|
|
reg [ 7:0] bypass_bit_counter = 'b0;
|
|
reg [ 2:0] write_data_bit_counter = 'b0;
|
|
reg [ 2:0] read_data_bit_counter = 'b0;
|
|
reg [ 3:0] header_in_bit_counter = 'b0;
|
|
reg [ 3:0] header_out_bit_counter = 'b0;
|
|
reg [18:0] scan_length_byte_counter = 'b0;
|
|
reg [18:0] valid_write_data_length_byte_counter = 'b0;
|
|
|
|
reg write_data_valid = 'b0;
|
|
reg read_data_valid = 'b0;
|
|
reg read_data_all_valid = 'b0;
|
|
|
|
reg decode_header_1 = 'b0;
|
|
reg decode_header_2 = 'b0;
|
|
|
|
wire write_data_byte_aligned;
|
|
wire read_data_byte_aligned;
|
|
wire padded_bit_byte_aligned;
|
|
wire bytestream_end;
|
|
|
|
assign write_data_byte_aligned = (write_data_bit_counter == 1);
|
|
assign read_data_byte_aligned = (read_data_bit_counter == 1);
|
|
assign padded_bit_byte_aligned = (padded_bit_counter[2:0] == 'b0);
|
|
assign bytestream_end = (scan_length_byte_counter == 'b0);
|
|
|
|
reg [ 7:0] offset = 'b0;
|
|
reg [15:0] header_in = 'b0;
|
|
|
|
reg [9:0] scan_length = 'b0;
|
|
reg [2:0] read_data_length = 'b0;
|
|
reg [2:0] write_data_length = 'b0;
|
|
|
|
wire [7:0] idle_inserter_sink_data;
|
|
wire idle_inserter_sink_valid;
|
|
wire idle_inserter_sink_ready;
|
|
wire [7:0] idle_inserter_source_data;
|
|
reg idle_inserter_source_ready = 'b0;
|
|
reg [7:0] idle_remover_sink_data = 'b0;
|
|
reg idle_remover_sink_valid = 'b0;
|
|
wire [7:0] idle_remover_source_data;
|
|
wire idle_remover_source_valid;
|
|
|
|
assign source_data = idle_remover_source_data;
|
|
assign source_valid = idle_remover_source_valid;
|
|
assign sink_ready = idle_inserter_sink_ready;
|
|
assign idle_inserter_sink_data = sink_data;
|
|
assign idle_inserter_sink_valid = sink_valid;
|
|
|
|
reg clock_sensor = 'b0;
|
|
reg clock_to_sample_div2 = 'b0;
|
|
(* altera_attribute = {"-name GLOBAL_SIGNAL OFF"}*) reg clock_sense_reset_n = 'b1;
|
|
|
|
wire data_available;
|
|
|
|
assign data_available = sink_valid;
|
|
|
|
wire [18:0] decoded_scan_length;
|
|
wire [18:0] decoded_write_data_length;
|
|
wire [18:0] decoded_read_data_length;
|
|
|
|
assign decoded_scan_length = { scan_length, {8{1'b1}} };
|
|
// +-------------------+----------------+---------------------+
|
|
// | scan_length | Length (bytes) | decoded_scan_length |
|
|
// +-------------------+----------------+---------------------+
|
|
// | 0x0 | 256 | 0x0ff (255) |
|
|
// | 0x1 | 512 | 0x1ff (511) |
|
|
// | 0x2 | 768 | 0x2ff (767) |
|
|
// | . | . | . |
|
|
// | 0x3ff | 256k | 0x3ff (256k-1) |
|
|
// +-------------------+----------------+---------------------+
|
|
|
|
// TODO: use look up table to save LEs?
|
|
// Decoded value is correct except for 0x7
|
|
assign decoded_write_data_length = (write_data_length == 0) ? 19'h0 : (19'h00080 << write_data_length);
|
|
assign decoded_read_data_length = (read_data_length == 0) ? 19'h0 : (19'h00080 << read_data_length);
|
|
// +-------------------+---------------+---------------------------+
|
|
// | read_data_length | Length | decoded_read_data_length |
|
|
// | write_data_length | (bytes) | decoded_write_data_length |
|
|
// +-------------------+---------------+---------------------------+
|
|
// | 0x0 | 0 | 0x0000 (0) |
|
|
// | 0x1 | 256 | 0x0100 (256) |
|
|
// | 0x2 | 512 | 0x0200 (512) |
|
|
// | 0x3 | 1k | 0x0400 (1024) |
|
|
// | 0x4 | 2k | 0x0800 (2048) |
|
|
// | 0x5 | 4k | 0x1000 (4096) |
|
|
// | 0x6 | 8k | 0x2000 (8192) |
|
|
// | 0x7 | scan_length | invalid |
|
|
// +-------------------+---------------+---------------------------+
|
|
|
|
wire clock_sensor_sync;
|
|
wire reset_to_sample_sync;
|
|
wire clock_to_sample_div2_sync;
|
|
wire clock_sense_reset_n_sync;
|
|
|
|
|
|
altera_std_synchronizer #(.depth(SYSCLK_TO_TCK_SYNC_DEPTH)) clock_sensor_synchronizer (
|
|
.clk(tck),
|
|
.reset_n(1'b1),
|
|
.din(clock_sensor),
|
|
.dout(clock_sensor_sync));
|
|
|
|
altera_std_synchronizer #(.depth(SYSCLK_TO_TCK_SYNC_DEPTH)) reset_to_sample_synchronizer (
|
|
.clk(tck),
|
|
.reset_n(1'b1),
|
|
.din(reset_to_sample),
|
|
.dout(reset_to_sample_sync));
|
|
|
|
altera_std_synchronizer #(.depth(SYSCLK_TO_TCK_SYNC_DEPTH)) clock_to_sample_div2_synchronizer (
|
|
.clk(tck),
|
|
.reset_n(1'b1),
|
|
.din(clock_to_sample_div2),
|
|
.dout(clock_to_sample_div2_sync));
|
|
|
|
altera_std_synchronizer #(.depth(TCK_TO_SYSCLK_SYNC_DEPTH)) clock_sense_reset_n_synchronizer (
|
|
.clk(clock_to_sample),
|
|
.reset_n(clock_sense_reset_n),
|
|
.din(1'b1),
|
|
.dout(clock_sense_reset_n_sync));
|
|
|
|
always @ (posedge clock_to_sample or negedge clock_sense_reset_n_sync) begin
|
|
if (~clock_sense_reset_n_sync) begin
|
|
clock_sensor <= 1'b0;
|
|
end else begin
|
|
clock_sensor <= 1'b1;
|
|
end
|
|
end
|
|
|
|
always @ (posedge clock_to_sample) begin
|
|
clock_to_sample_div2 <= ~clock_to_sample_div2;
|
|
end
|
|
|
|
always @ (posedge tck) begin
|
|
|
|
idle_remover_sink_valid <= 1'b0;
|
|
idle_inserter_source_ready <= 1'b0;
|
|
|
|
// Data mode sourcing (write)
|
|
|
|
// offset(rounded 8) m-i i 16 offset
|
|
// +------------+-----------+------------------+--------+------------+
|
|
// tdi -> | padded_bit | undefined | valid_write_data | header | bypass_bit |
|
|
// +------------+-----------+------------------+--------+------------+
|
|
// Data mode DR data stream write format (as seen by hardware)
|
|
//
|
|
if (ir_in == DATA) begin
|
|
|
|
|
|
if (virtual_state_cdr) begin
|
|
if (offset == 'b0) begin
|
|
write_state <= ST_HEADER_1;
|
|
end else begin
|
|
write_state <= ST_BYPASS;
|
|
end
|
|
// 8-bit bypass_bit_counter
|
|
bypass_bit_counter <= offset;
|
|
// 4-bit header_in_bit_counter
|
|
header_in_bit_counter <= 15;
|
|
// 3-bit write_data_bit_counter
|
|
write_data_bit_counter <= 0;
|
|
// Reset the registers
|
|
// TODO: not necessarily all, reduce LE
|
|
decode_header_1 <= 1'b0;
|
|
decode_header_2 <= 1'b0;
|
|
read_data_all_valid <= 1'b0;
|
|
valid_write_data_length_byte_counter <= 0;
|
|
end
|
|
|
|
if (virtual_state_sdr) begin
|
|
// Discard bypass bits, then decode the 16-bit header
|
|
// 3 3 10
|
|
// +-------------------+------------------+-------------+
|
|
// | write_data_length | read_data_length | scan_length |
|
|
// +-------------------+------------------+-------------+
|
|
// Header format
|
|
|
|
case (write_state)
|
|
ST_BYPASS: begin
|
|
// Discard the bypass bit
|
|
bypass_bit_counter <= bypass_bit_counter - 1'b1;
|
|
if (bypass_bit_counter == 1) begin
|
|
write_state <= ST_HEADER_1;
|
|
end
|
|
end
|
|
// Shift the scan_length and read_data_length
|
|
ST_HEADER_1: begin
|
|
// TODO: header_in can be shorter
|
|
// Shift into header_in
|
|
header_in <= {tdi, header_in[15:1]};
|
|
header_in_bit_counter <= header_in_bit_counter - 1'b1;
|
|
if (header_in_bit_counter == 3) begin
|
|
read_data_length <= {tdi, header_in[15:14]};
|
|
scan_length <= header_in[13:4];
|
|
write_state <= ST_HEADER_2;
|
|
decode_header_1 <= 1'b1;
|
|
end
|
|
end
|
|
// Shift the write_data_length
|
|
ST_HEADER_2: begin
|
|
// Shift into header_in
|
|
header_in <= {tdi, header_in[15:1]};
|
|
header_in_bit_counter <= header_in_bit_counter - 1'b1;
|
|
// Decode read_data_length and scan_length
|
|
if (decode_header_1) begin
|
|
decode_header_1 <= 1'b0;
|
|
// Set read_data_all_valid
|
|
if (read_data_length == 3'b111) begin
|
|
read_data_all_valid <= 1'b1;
|
|
end
|
|
// Load scan_length_byte_counter
|
|
scan_length_byte_counter <= decoded_scan_length;
|
|
end
|
|
if (header_in_bit_counter == 0) begin
|
|
write_data_length <= {tdi, header_in[15:14]};
|
|
write_state <= ST_WRITE_DATA;
|
|
decode_header_2 <= 1'b1;
|
|
end
|
|
end
|
|
// Shift the valid_write_data
|
|
ST_WRITE_DATA: begin
|
|
// Shift into dr_data_in
|
|
dr_data_in <= {tdi, dr_data_in[7:1]};
|
|
// Decode write_data_length
|
|
if (decode_header_2) begin
|
|
decode_header_2 <= 1'b0;
|
|
// Load valid_write_data_length_byte_counter
|
|
case (write_data_length)
|
|
3'b111: valid_write_data_length_byte_counter <= decoded_scan_length + 1'b1;
|
|
3'b000: valid_write_data_length_byte_counter <= 'b0;
|
|
default: valid_write_data_length_byte_counter <= decoded_write_data_length;
|
|
endcase
|
|
end
|
|
write_data_bit_counter <= write_data_bit_counter - 1'b1;
|
|
write_data_valid <= (valid_write_data_length_byte_counter != 0);
|
|
// Feed the data to the idle remover
|
|
if (write_data_byte_aligned && write_data_valid) begin
|
|
valid_write_data_length_byte_counter <= valid_write_data_length_byte_counter - 1'b1;
|
|
idle_remover_sink_valid <= 1'b1;
|
|
idle_remover_sink_data <= {tdi, dr_data_in[7:1]};
|
|
end
|
|
end
|
|
endcase
|
|
end
|
|
|
|
end
|
|
|
|
// Data mode sinking (read)
|
|
|
|
// i m-i offset(rounded 8) 16
|
|
// +-----------------+-----------+------------+--------+
|
|
// | valid_read_data | undefined | padded_bit | header | -> tdo
|
|
// +-----------------+-----------+------------+--------+
|
|
// Data mode DR data stream read format (as seen by hardware)
|
|
//
|
|
if (ir_in == DATA) begin
|
|
|
|
if (virtual_state_cdr) begin
|
|
|
|
read_state <= ST_HEADER;
|
|
// Offset is rounded to nearest ceiling x8 to byte-align padded bits
|
|
// 9-bit padded_bit_counter
|
|
if (|offset[2:0]) begin
|
|
padded_bit_counter[8:3] <= offset[7:3] + 1'b1;
|
|
padded_bit_counter[2:0] <= 3'b0;
|
|
end else begin
|
|
padded_bit_counter <= {1'b0, offset};
|
|
end
|
|
// 4-bit header_out_bit_counter
|
|
header_out_bit_counter <= 0;
|
|
// 3-bit read_data_bit_counter
|
|
read_data_bit_counter <= 0;
|
|
// Load the data_available bit into header
|
|
dr_data_out <= {{7{1'b0}}, data_available};
|
|
read_data_valid <= 0;
|
|
|
|
end
|
|
|
|
if (virtual_state_sdr) begin
|
|
// 10 1
|
|
// +-----------------------------------+----------------+
|
|
// | reserved | data_available |
|
|
// +-----------------------------------+----------------+
|
|
// Header format
|
|
|
|
dr_data_out <= {1'b0, dr_data_out[7:1]};
|
|
case (read_state)
|
|
// Shift the scan_length and read_data_length
|
|
ST_HEADER: begin
|
|
header_out_bit_counter <= header_out_bit_counter - 1'b1;
|
|
// Retrieve data from idle inserter for the next shift if no paddded bits
|
|
if (header_out_bit_counter == 2) begin
|
|
if (padded_bit_counter == 0) begin
|
|
idle_inserter_source_ready <= read_data_all_valid;
|
|
end
|
|
end
|
|
if (header_out_bit_counter == 1) begin
|
|
if (padded_bit_counter == 0) begin
|
|
read_state <= ST_READ_DATA;
|
|
read_data_valid <= read_data_all_valid || (scan_length_byte_counter<=decoded_read_data_length+1);
|
|
dr_data_out <= read_data_all_valid ? idle_inserter_source_data : 8'h4a;
|
|
end else begin
|
|
read_state <= ST_PADDED;
|
|
padded_bit_counter <= padded_bit_counter - 1'b1;
|
|
idle_inserter_source_ready <= 1'b0;
|
|
dr_data_out <= 8'h4a;
|
|
end
|
|
end
|
|
end
|
|
ST_PADDED: begin
|
|
padded_bit_counter <= padded_bit_counter - 1'b1;
|
|
if (padded_bit_byte_aligned) begin
|
|
// Load idle character into data register
|
|
dr_data_out <= 8'h4a;
|
|
end
|
|
// Retrieve data from idle inserter for the next shift when padded bits finish
|
|
if (padded_bit_counter == 1) begin
|
|
idle_inserter_source_ready <= read_data_all_valid;
|
|
end
|
|
if (padded_bit_counter == 0) begin // TODO: might make use of (padded_bit_counter[8:3]&padded_bit_byte_aligned)
|
|
read_state <= ST_READ_DATA;
|
|
read_data_valid <= read_data_all_valid || (scan_length_byte_counter<=decoded_read_data_length+1);
|
|
dr_data_out <= read_data_all_valid ? idle_inserter_source_data : 8'h4a;
|
|
end
|
|
end
|
|
ST_READ_DATA: begin
|
|
read_data_bit_counter <= read_data_bit_counter - 1'b1;
|
|
// Retrieve data from idle inserter just before read_data_byte_aligned
|
|
if (read_data_bit_counter == 2) begin
|
|
// Assert ready to retrieve data from idle inserter only when the bytestream has not ended,
|
|
// data is valid (idle_inserter is always valid) and data is needed (read_data_valid)
|
|
idle_inserter_source_ready <= bytestream_end ? 1'b0 : read_data_valid;
|
|
end
|
|
if (read_data_byte_aligned) begin
|
|
// Note that bytestream_end is driven by scan_length_byte_counter
|
|
if (~bytestream_end) begin
|
|
scan_length_byte_counter <= scan_length_byte_counter - 1'b1;
|
|
end
|
|
read_data_valid <= read_data_all_valid || (scan_length_byte_counter<=decoded_read_data_length+1);
|
|
// Load idle character if bytestream has ended, else get data from the idle inserter
|
|
dr_data_out <= (read_data_valid & ~bytestream_end) ? idle_inserter_source_data : 8'h4a;
|
|
end
|
|
end
|
|
endcase
|
|
|
|
end
|
|
|
|
end
|
|
|
|
// Loopback mode
|
|
if (ir_in == LOOPBACK) begin
|
|
if (virtual_state_cdr) begin
|
|
dr_loopback <= 1'b0; // capture 0
|
|
end
|
|
if (virtual_state_sdr) begin
|
|
// Shift dr_loopback
|
|
dr_loopback <= tdi;
|
|
end
|
|
end
|
|
|
|
// Debug mode
|
|
if (ir_in == DEBUG) begin
|
|
if (virtual_state_cdr) begin
|
|
dr_debug <= {clock_sensor_sync, clock_to_sample_div2_sync, reset_to_sample_sync};
|
|
end
|
|
if (virtual_state_sdr) begin
|
|
// Shift dr_debug
|
|
dr_debug <= {1'b0, dr_debug[2:1]}; // tdi is ignored
|
|
end
|
|
if (virtual_state_udr) begin
|
|
clock_sense_reset_n <= 1'b0;
|
|
end else begin
|
|
clock_sense_reset_n <= 1'b1;
|
|
end
|
|
end
|
|
|
|
// Info mode
|
|
if (ir_in == INFO) begin
|
|
if (virtual_state_cdr) begin
|
|
dr_info <= {PURPOSE[2:0], UPSTREAM_ENCODED_SIZE[3:0], DOWNSTREAM_ENCODED_SIZE[3:0]};
|
|
end
|
|
if (virtual_state_sdr) begin
|
|
// Shift dr_info
|
|
dr_info <= {1'b0, dr_info[10:1]}; // tdi is ignored
|
|
end
|
|
end
|
|
|
|
// Control mode
|
|
if (ir_in == CONTROL) begin
|
|
if (virtual_state_cdr) begin
|
|
dr_control <= 'b0; // capture 0
|
|
end
|
|
if (virtual_state_sdr) begin
|
|
// Shift dr_control
|
|
dr_control <= {tdi, dr_control[8:1]};
|
|
end
|
|
if (virtual_state_udr) begin
|
|
// Update resetrequest and offset
|
|
{resetrequest, offset} <= dr_control;
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
always @ * begin
|
|
if (virtual_state_sdr) begin
|
|
case (ir_in)
|
|
DATA: tdo <= dr_data_out[0];
|
|
LOOPBACK: tdo <= dr_loopback;
|
|
DEBUG: tdo <= dr_debug[0];
|
|
INFO: tdo <= dr_info[0];
|
|
CONTROL: tdo <= dr_control[0];
|
|
MGMT: tdo <= dr_mgmt[0];
|
|
default: tdo <= 1'b0;
|
|
endcase
|
|
end else begin
|
|
tdo <= 1'b0;
|
|
end
|
|
end
|
|
|
|
// Idle Remover
|
|
altera_avalon_st_idle_remover idle_remover (
|
|
// Interface: clk
|
|
.clk (tck),
|
|
.reset_n (reset_n),
|
|
|
|
// Interface: ST in
|
|
.in_ready (), // left disconnected
|
|
.in_valid (idle_remover_sink_valid),
|
|
.in_data (idle_remover_sink_data),
|
|
|
|
// Interface: ST out
|
|
.out_ready (1'b1), // downstream is expected to be always ready
|
|
.out_valid (idle_remover_source_valid),
|
|
.out_data (idle_remover_source_data)
|
|
);
|
|
|
|
// Idle Inserter
|
|
altera_avalon_st_idle_inserter idle_inserter (
|
|
// Interface: clk
|
|
.clk (tck),
|
|
.reset_n (reset_n),
|
|
|
|
// Interface: ST in
|
|
.in_ready (idle_inserter_sink_ready),
|
|
.in_valid (idle_inserter_sink_valid),
|
|
.in_data (idle_inserter_sink_data),
|
|
|
|
// Interface: ST out
|
|
.out_ready (idle_inserter_source_ready),
|
|
.out_valid (),
|
|
.out_data (idle_inserter_source_data)
|
|
);
|
|
|
|
generate
|
|
if (MGMT_CHANNEL_WIDTH > 0)
|
|
begin : has_mgmt
|
|
reg [MGMT_CHANNEL_WIDTH+2:0] mgmt_out = 'b0;
|
|
reg mgmt_toggle = 1'b0;
|
|
wire mgmt_toggle_sync;
|
|
reg mgmt_toggle_prev;
|
|
always @ (posedge tck) begin
|
|
// Debug mode
|
|
if (ir_in == MGMT) begin
|
|
if (virtual_state_cdr) begin
|
|
dr_mgmt <= 'b0;
|
|
dr_mgmt[MGMT_CHANNEL_WIDTH+2] <= 1'b1;
|
|
end
|
|
if (virtual_state_sdr) begin
|
|
// Shift dr_debug
|
|
dr_mgmt <= {tdi, dr_mgmt[MGMT_CHANNEL_WIDTH+2:1]};
|
|
end
|
|
if (virtual_state_udr) begin
|
|
mgmt_out <= dr_mgmt;
|
|
mgmt_toggle <= mgmt_out[MGMT_CHANNEL_WIDTH+2] ? 1'b0 : ~mgmt_toggle;
|
|
end
|
|
end
|
|
end
|
|
|
|
altera_std_synchronizer #(.depth(TCK_TO_SYSCLK_SYNC_DEPTH)) debug_reset_synchronizer (
|
|
.clk(clock_to_sample),
|
|
.reset_n(1'b1),
|
|
.din(mgmt_out[MGMT_CHANNEL_WIDTH+2]),
|
|
.dout(debug_reset));
|
|
|
|
altera_std_synchronizer #(.depth(TCK_TO_SYSCLK_SYNC_DEPTH)) mgmt_toggle_synchronizer (
|
|
.clk(clock_to_sample),
|
|
.reset_n(1'b1),
|
|
.din(mgmt_toggle),
|
|
.dout(mgmt_toggle_sync));
|
|
|
|
always @ (posedge clock_to_sample or posedge debug_reset) begin
|
|
if (debug_reset) begin
|
|
mgmt_valid <= 1'b0;
|
|
mgmt_toggle_prev <= 1'b0;
|
|
end else begin
|
|
if ((mgmt_toggle_sync ^ mgmt_toggle_prev) && mgmt_out[MGMT_CHANNEL_WIDTH+1]) begin
|
|
mgmt_valid <= 1'b1;
|
|
mgmt_channel <= mgmt_out[MGMT_CHANNEL_WIDTH:1];
|
|
mgmt_data <= mgmt_out[0];
|
|
end else begin
|
|
mgmt_valid <= 1'b0;
|
|
end
|
|
mgmt_toggle_prev <= mgmt_toggle_sync;
|
|
end
|
|
end
|
|
|
|
end
|
|
else
|
|
begin : no_mgmt
|
|
always @ (posedge tck) begin
|
|
dr_mgmt[0] <= 1'b0;
|
|
end
|
|
assign debug_reset = 1'b0;
|
|
always @ (posedge clock_to_sample) begin
|
|
mgmt_valid <= 1'b0;
|
|
mgmt_data <= 'b0;
|
|
mgmt_channel <= 'b0;
|
|
end
|
|
end
|
|
endgenerate
|
|
|
|
endmodule
|