// ============================================================================= // Module Name: IPat_JtagCont // Revision: 20230618a // History: // + 20230618a: State machine bug fixed // + 20220504a: Initial Revision // Author: Altmo toolbox // Description: // + JTAG Controller // ============================================================================= `timescale 1ns/1ns module IPat_JtagCont ( input TCK, // Test Access Port: Clock input TMS, // Test Access Port: Test mode select input TDI, // Test Access Port: Serial data input output TDO, // Test Access Port: Serial data output input TRST, // Test Access Port: Contoroller reset output tdo_en_n, // TDO output enable control (0:enable, 1:disable) output bsr_si, // Serial data output to BSR chain input bsr_so, // Serial data input from BSR chain output bsr_capture, // BSR capture control output bsr_shift, // BSR shift control output bsr_update, // BSR update control output bsr_mode_i, // BSR (Input: Pad to Core) mode control output bsr_mode_o, // BSR (Output: Core to Pad) mode control output bsr_mode_e, // BSR (Output Enable) mode control (0:enable, 1:disable) output bsr_highz // BSR force highz output ); // =========================================================================== // Parameters(1): Following parameters should be modified for target IC. // =========================================================================== parameter P_WD_IR = 6; // Bit width of IR(Instruction registers) parameter P_IR_IDCODE = 6'b001001; // IR value of IDCODE instruction parameter P_IR_SAMPLE = 6'b000001; // IR value of SAMPLE/PRELOAD instruction parameter P_IR_EXTEST = 6'b001111; // IR value of EXTEST instruction parameter P_IR_BYPASS = 6'b111111; // IR value of BYPASS instruction parameter P_IR_HIGHZ = 6'b001010; // IR value of HIGHZ instruction parameter P_IR_CLAMP = 6'b001011; // IR value of CLAMP instruction parameter P_EN_HIGHZ = 1'b1; // HIGHZ inst. is 1'b1:valid, 1'b0:invalid. parameter P_EN_CLAMP = 1'b1; // CLAMP inst. is 1'b1:valid, 1'b0:invalid. parameter P_WD_DEVID = 32; // Bit width of DEVICE_ID registers parameter P_DEVICE_ID = 32'bxxxx_0100000_000000100_00001001001_1; // DEVICE_ID // |~~~ |~~~~~~ |~~~~~~~~ |~~~~~~~~~~ // | | | Manufacturer // | | Part Number(Array size) // | Part Number(Family) // Version // =========================================================================== // Parameters(2): Following parameters are able to be assigned for all IC. // =========================================================================== parameter P_WD_STATE = 4; // Bit width of r_state(State machine registers) parameter P_STATE_RESET = 4'b0000; // r_state value of Test-Logic-Reset parameter P_STATE_IDLE = 4'b0001; // r_state value of Run-Test/Idle parameter P_STATE_SELECT_DR = 4'b0010; // r_state value of Select-DR-Scan parameter P_STATE_CAPTURE_DR = 4'b0011; // r_state value of Capture-DR parameter P_STATE_SHIFT_DR = 4'b0100; // r_state value of Shift-DR parameter P_STATE_EXIT1_DR = 4'b0101; // r_state value of Exit1-DR parameter P_STATE_PAUSE_DR = 4'b0110; // r_state value of Pause-DR parameter P_STATE_EXIT2_DR = 4'b0111; // r_state value of Exit2-DR parameter P_STATE_UPDATE_DR = 4'b1000; // r_state value of Update-DR parameter P_STATE_SELECT_IR = 4'b1001; // r_state value of Select-IR-Scan parameter P_STATE_CAPTURE_IR = 4'b1010; // r_state value of Capture-IR parameter P_STATE_SHIFT_IR = 4'b1011; // r_state value of Shift-IR parameter P_STATE_EXIT1_IR = 4'b1100; // r_state value of Exit1-IR parameter P_STATE_PAUSE_IR = 4'b1101; // r_state value of Pause-IR parameter P_STATE_EXIT2_IR = 4'b1110; // r_state value of Exit2-IR parameter P_STATE_UPDATE_IR = 4'b1111; // r_state value of Update-IR // --------------------------------------------------------------------------- // Local parameters // --------------------------------------------------------------------------- parameter u_dly = 1; // unit delay for registers input // =========================================================================== // Internal control signals // =========================================================================== wire w_capture_devid; // Capture control of r_devid chain wire w_shift_devid; // Shift control of r_devid chain wire w_shift_bypass; // Shift control of r_bypass chain wire w_capture_ir; // Capture control of r_ir_capture chain wire w_shift_ir; // Shift control of r_ir_capture chain wire w_update_ir; // Update control of r_ir_update registers // =========================================================================== // Registers // =========================================================================== reg [P_WD_STATE-1:0] r_state; // JTAG state machine registers reg r_bypass; // Bypass chain register reg [P_WD_DEVID-1:0] r_devid; // DEVICE_ID chain registers reg [P_WD_IR-1 :0] r_ir_capture; // IR capture and shift registers reg [P_WD_IR-1 :0] r_ir_update; // IR update registers reg r_tdo_lockup; // TDO output lockup register reg r_tdo_en_n; // TDO output enable register // --------------------------------------------------------------------------- // Input signals for above registers // --------------------------------------------------------------------------- wire [P_WD_STATE-1:0] w_r_state; wire w_r_bypass; wire [P_WD_DEVID-1:0] w_r_devid; wire [P_WD_IR-1 :0] w_r_ir_capture; wire [P_WD_IR-1 :0] w_r_ir_update; wire w_r_tdo_lockup; wire w_r_tdo_en_n; // --------------------------------------------------------------------------- // Decode/Flag signals for internal logic description // --------------------------------------------------------------------------- // IR wire w_ir_idcode; assign w_ir_idcode = (r_ir_update == P_IR_IDCODE); wire w_ir_sample; assign w_ir_sample = (r_ir_update == P_IR_SAMPLE); wire w_ir_extest; assign w_ir_extest = (r_ir_update == P_IR_EXTEST); wire w_ir_bypass; assign w_ir_bypass = (r_ir_update == P_IR_BYPASS); wire w_ir_highz; generate if (P_EN_HIGHZ) assign w_ir_highz = (r_ir_update == P_IR_HIGHZ ); else assign w_ir_highz = 1'b0; endgenerate wire w_ir_clamp; generate if (P_EN_CLAMP) assign w_ir_clamp = (r_ir_update == P_IR_CLAMP ); else assign w_ir_clamp = 1'b0; endgenerate // State machine wire w_state_reset; assign w_state_reset = (r_state == P_STATE_RESET ); wire w_state_idle; assign w_state_idle = (r_state == P_STATE_IDLE ); wire w_state_select_dr; assign w_state_select_dr = (r_state == P_STATE_SELECT_DR ); wire w_state_capture_dr; assign w_state_capture_dr = (r_state == P_STATE_CAPTURE_DR); wire w_state_shift_dr; assign w_state_shift_dr = (r_state == P_STATE_SHIFT_DR ); wire w_state_exit1_dr; assign w_state_exit1_dr = (r_state == P_STATE_EXIT1_DR ); wire w_state_pause_dr; assign w_state_pause_dr = (r_state == P_STATE_PAUSE_DR ); wire w_state_exit2_dr; assign w_state_exit2_dr = (r_state == P_STATE_EXIT2_DR ); wire w_state_update_dr; assign w_state_update_dr = (r_state == P_STATE_UPDATE_DR ); wire w_state_select_ir; assign w_state_select_ir = (r_state == P_STATE_SELECT_IR ); wire w_state_capture_ir; assign w_state_capture_ir = (r_state == P_STATE_CAPTURE_IR); wire w_state_shift_ir; assign w_state_shift_ir = (r_state == P_STATE_SHIFT_IR ); wire w_state_exit1_ir; assign w_state_exit1_ir = (r_state == P_STATE_EXIT1_IR ); wire w_state_pause_ir; assign w_state_pause_ir = (r_state == P_STATE_PAUSE_IR ); wire w_state_exit2_ir; assign w_state_exit2_ir = (r_state == P_STATE_EXIT2_IR ); wire w_state_update_ir; assign w_state_update_ir = (r_state == P_STATE_UPDATE_IR ); // --------------------------------------------------------------------------- // Logic descriptions for control signals // --------------------------------------------------------------------------- assign w_capture_ir = w_state_capture_ir; assign w_shift_ir = w_state_shift_ir; assign w_update_ir = w_state_update_ir; assign w_capture_devid = w_ir_idcode & w_state_capture_dr; assign w_shift_devid = w_ir_idcode & w_state_shift_dr; assign w_shift_bypass = (w_ir_bypass | w_ir_highz | w_ir_clamp) & w_state_shift_dr; assign bsr_capture = (w_ir_extest | w_ir_sample) & w_state_capture_dr; assign bsr_shift = (w_ir_extest | w_ir_sample) & w_state_shift_dr; assign bsr_update = (w_ir_extest | w_ir_sample) & w_state_update_dr; assign bsr_mode_i = 1'b0; // IPat_JtagCont does not support RUNBIST and INTEST instructions assign bsr_mode_o = w_ir_extest | w_ir_clamp; assign bsr_mode_e = w_ir_extest | w_ir_clamp; assign bsr_highz = w_ir_highz; assign bsr_si = TDI; // --------------------------------------------------------------------------- // JTAG state machine (does not have asynchronous reset) // --------------------------------------------------------------------------- // ------------------------------------------------------------------------- // synthesis translate_off // ------------------------------------------------------------------------- // This JTAG controller does not have TRST port // so following statements sets initial value to avoid simulation troubles. localparam LP_INITIAL_STATE = P_STATE_CAPTURE_DR; initial begin r_state = LP_INITIAL_STATE; end // ------------------------------------------------------------------------- // synthesis translate_on // ------------------------------------------------------------------------- always @(posedge TCK or negedge TRST) begin if (TRST == 1'b0) begin r_state <= #u_dly P_STATE_RESET; end else begin case (r_state) P_STATE_RESET: r_state <= #u_dly (TMS==1'b1)? P_STATE_RESET : P_STATE_IDLE; P_STATE_IDLE: r_state <= #u_dly (TMS==1'b1)? P_STATE_SELECT_DR : P_STATE_IDLE; P_STATE_SELECT_DR: r_state <= #u_dly (TMS==1'b1)? P_STATE_SELECT_IR : P_STATE_CAPTURE_DR; P_STATE_CAPTURE_DR: r_state <= #u_dly (TMS==1'b1)? P_STATE_EXIT1_DR : P_STATE_SHIFT_DR; P_STATE_SHIFT_DR: r_state <= #u_dly (TMS==1'b1)? P_STATE_EXIT1_DR : P_STATE_SHIFT_DR; P_STATE_EXIT1_DR: r_state <= #u_dly (TMS==1'b1)? P_STATE_UPDATE_DR : P_STATE_PAUSE_DR; P_STATE_PAUSE_DR: r_state <= #u_dly (TMS==1'b1)? P_STATE_EXIT2_DR : P_STATE_PAUSE_DR; P_STATE_EXIT2_DR: r_state <= #u_dly (TMS==1'b1)? P_STATE_UPDATE_DR : P_STATE_SHIFT_DR; P_STATE_UPDATE_DR: r_state <= #u_dly (TMS==1'b1)? P_STATE_SELECT_DR : P_STATE_IDLE; P_STATE_SELECT_IR: r_state <= #u_dly (TMS==1'b1)? P_STATE_RESET : P_STATE_CAPTURE_IR; P_STATE_CAPTURE_IR: r_state <= #u_dly (TMS==1'b1)? P_STATE_EXIT1_IR : P_STATE_SHIFT_IR; P_STATE_SHIFT_IR: r_state <= #u_dly (TMS==1'b1)? P_STATE_EXIT1_IR : P_STATE_SHIFT_IR; P_STATE_EXIT1_IR: r_state <= #u_dly (TMS==1'b1)? P_STATE_UPDATE_IR : P_STATE_PAUSE_IR; P_STATE_PAUSE_IR: r_state <= #u_dly (TMS==1'b1)? P_STATE_EXIT2_IR : P_STATE_PAUSE_IR; P_STATE_EXIT2_IR: r_state <= #u_dly (TMS==1'b1)? P_STATE_UPDATE_IR : P_STATE_SHIFT_IR; P_STATE_UPDATE_IR: r_state <= #u_dly (TMS==1'b1)? P_STATE_SELECT_DR : P_STATE_IDLE; endcase end end // --------------------------------------------------------------------------- // Bypass register // --------------------------------------------------------------------------- always @(posedge TCK or negedge TRST or posedge w_state_reset) begin if (TRST == 1'b0) begin r_bypass <= #u_dly 1'b0; end else if (w_state_reset==1'b1) begin r_bypass <= #u_dly 1'b0; end else begin r_bypass <= #u_dly w_r_bypass; end end assign w_r_bypass = (w_shift_bypass==1'b1)? TDI : r_bypass; // --------------------------------------------------------------------------- // DEVICE_ID registers // --------------------------------------------------------------------------- always @(posedge TCK or negedge TRST or posedge w_state_reset) begin if (TRST == 1'b0) begin r_devid <= #u_dly P_DEVICE_ID; end else if (w_state_reset==1'b1) begin r_devid <= #u_dly P_DEVICE_ID; end else begin r_devid <= #u_dly w_r_devid; end end assign w_r_devid = (w_capture_devid==1'b1)? P_DEVICE_ID : (w_shift_devid ==1'b1)? {TDI, r_devid[P_WD_DEVID-1:1]} : // LSB-first r_devid; // --------------------------------------------------------------------------- // IR registers // --------------------------------------------------------------------------- always @(posedge TCK or negedge TRST or posedge w_state_reset) begin if (TRST == 1'b0) begin r_ir_capture <= #u_dly {P_WD_IR{1'b0}}; r_ir_update <= #u_dly P_IR_IDCODE; end else if (w_state_reset==1'b1) begin r_ir_capture <= #u_dly {P_WD_IR{1'b0}}; r_ir_update <= #u_dly P_IR_IDCODE; end else begin r_ir_capture <= #u_dly w_r_ir_capture; r_ir_update <= #u_dly w_r_ir_update; end end assign w_r_ir_capture = (w_capture_ir==1'b1)? {P_WD_IR{1'bx}} : (w_shift_ir ==1'b1)? {TDI, r_ir_capture[P_WD_IR-1:1]} : // LSB-first r_ir_capture; assign w_r_ir_update = (w_update_ir==1'b1)? r_ir_capture : r_ir_update; // --------------------------------------------------------------------------- // TDO lockup register (TCK Negedge) // --------------------------------------------------------------------------- always @(negedge TCK or negedge TRST or posedge w_state_reset) begin if (TRST == 1'b0) begin r_tdo_lockup <= #u_dly 1'b0; end else if (w_state_reset==1'b1) begin r_tdo_lockup <= #u_dly 1'b0; end else begin r_tdo_lockup <= #u_dly w_r_tdo_lockup; end end assign TDO = r_tdo_lockup; assign w_r_tdo_lockup = (w_state_shift_ir==1'b1)? r_ir_capture[0] : (w_ir_idcode==1'b1)? r_devid[0] : (w_ir_sample==1'b1)? bsr_so : (w_ir_extest==1'b1)? bsr_so : (w_ir_bypass==1'b1)? r_bypass : (w_ir_highz==1'b1)? r_bypass : (w_ir_clamp==1'b1)? r_bypass : r_tdo_lockup; // --------------------------------------------------------------------------- // TDO output enable lockup register (TCK Negedge) // --------------------------------------------------------------------------- always @(negedge TCK or negedge TRST or posedge w_state_reset) begin if (TRST == 1'b0) begin r_tdo_en_n <= #u_dly 1'b1; end else if (w_state_reset==1'b1) begin r_tdo_en_n <= #u_dly 1'b1; end else begin r_tdo_en_n <= #u_dly w_r_tdo_en_n; end end assign w_r_tdo_en_n = ~(w_state_shift_dr | w_state_shift_ir); assign tdo_en_n = r_tdo_en_n; endmodule