// See LICENSE.SiFive for license details. /* * TCP/IP controlled VPI JTAG Interface. * Based on Julius Baxter's work on jp_vpi.c * * Copyright (C) 2012 Franck Jullien, * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the names of the copyright holders nor the names of any * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ //VCS coverage exclude_file `define CMD_RESET 0 `define CMD_TMS_SEQ 1 `define CMD_SCAN_CHAIN 2 `define CMD_SCAN_CHAIN_FLIP_TMS 3 `define CMD_STOP_SIMU 4 module JTAGVPI #( parameter DEBUG_INFO = 0, parameter TP = 1, parameter TCK_HALF_PERIOD = 2,// 50, // Clock half period (Clock period = 100 ns => 10 MHz) parameter CMD_DELAY = 2, // 1000 parameter INIT_DELAY = 200 ) ( output jtag_TMS, output jtag_TCK, output jtag_TDI, input jtag_TDO_data, input jtag_TDO_driven, input enable, input init_done); reg tms; reg tck; reg tdi; wire tdo; assign jtag_TMS = tms; assign jtag_TCK = tck; assign jtag_TDI = tdi; assign tdo = jtag_TDO_driven ? jtag_TDO_data : 1'bz; integer cmd; integer length; integer nb_bits; reg [31:0] buffer_out [0:4095]; // Data storage from the jtag server reg [31:0] buffer_in [0:4095]; // Data storage to the jtag server integer flip_tms; reg [31:0] data_out; reg [31:0] data_in; integer debug; initial begin tck <= #TP 1'b0; tdi <= #TP 1'bz; tms <= #TP 1'b0; data_out <= 32'h0; data_in <= 32'h0; // Small delay to get past reset instability // before checking for init_done #INIT_DELAY wait(init_done) if($test$plusargs("jtag_vpi_enable")) main; end task main; begin $display("JTAG debug module with VPI interface enabled\n"); reset_tap; goto_run_test_idle_from_reset; while (1) begin // Check for incoming command // wait until a command is sent // poll with a delay here cmd = -1; while (cmd == -1) begin #CMD_DELAY $check_for_command(cmd, length, nb_bits, buffer_out); end // now switch on the command case (cmd) `CMD_RESET : begin if (DEBUG_INFO) $display("%t ----> CMD_RESET %h\n", $time, length); reset_tap; goto_run_test_idle_from_reset; end `CMD_TMS_SEQ : begin if (DEBUG_INFO) $display("%t ----> CMD_TMS_SEQ\n", $time); do_tms_seq; end `CMD_SCAN_CHAIN : begin if (DEBUG_INFO) $display("%t ----> CMD_SCAN_CHAIN\n", $time); flip_tms = 0; do_scan_chain; $send_result_to_server(length, buffer_in); end `CMD_SCAN_CHAIN_FLIP_TMS : begin if(DEBUG_INFO) $display("%t ----> CMD_SCAN_CHAIN\n", $time); flip_tms = 1; do_scan_chain; $send_result_to_server(length, buffer_in); end `CMD_STOP_SIMU : begin if(DEBUG_INFO) $display("%t ----> End of simulation\n", $time); $finish(); end default: begin $display("Somehow got to the default case in the command case statement."); $display("Command was: %x", cmd); $display("Exiting..."); $finish(); end endcase // case (cmd) end // while (1) end endtask // main // Generation of the TCK signal task gen_clk; input [31:0] number; integer i; begin for (i = 0; i < number; i = i + 1) begin #TCK_HALF_PERIOD tck <= 1; #TCK_HALF_PERIOD tck <= 0; end end endtask // TAP reset task reset_tap; begin if (DEBUG_INFO) $display("(%0t) Task reset_tap", $time); tms <= #1 1'b1; gen_clk(5); end endtask // Goes to RunTestIdle state task goto_run_test_idle_from_reset; begin if (DEBUG_INFO) $display("(%0t) Task goto_run_test_idle_from_reset", $time); tms <= #1 1'b0; gen_clk(1); end endtask // task do_tms_seq; integer i,j; reg [31:0] data; integer nb_bits_rem; integer nb_bits_in_this_byte; begin if (DEBUG_INFO) $display("(%0t) Task do_tms_seq of %d bits (length = %d)", $time, nb_bits, length); // Number of bits to send in the last byte nb_bits_rem = nb_bits % 8; for (i = 0; i < length; i = i + 1) begin // If we are in the last byte, we have to send only // nb_bits_rem bits. If not, we send the whole byte. nb_bits_in_this_byte = (i == (length - 1)) ? nb_bits_rem : 8; data = buffer_out[i]; for (j = 0; j < nb_bits_in_this_byte; j = j + 1) begin tms <= #1 1'b0; if (data[j] == 1) begin tms <= #1 1'b1; end gen_clk(1); end end tms <= #1 1'b0; end endtask // task do_scan_chain; integer _bit; integer nb_bits_rem; integer nb_bits_in_this_byte; integer index; begin if(DEBUG_INFO) $display("(%0t) Task do_scan_chain of %d bits (length = %d)", $time, nb_bits, length); // Number of bits to send in the last byte nb_bits_rem = nb_bits % 8; for (index = 0; index < length; index = index + 1) begin // If we are in the last byte, we have to send only // nb_bits_rem bits if it's not zero. // If not, we send the whole byte. nb_bits_in_this_byte = (index == (length - 1)) ? ((nb_bits_rem == 0) ? 8 : nb_bits_rem) : 8; data_out = buffer_out[index]; for (_bit = 0; _bit < nb_bits_in_this_byte; _bit = _bit + 1) begin tdi <= 1'b0; if (data_out[_bit] == 1'b1) begin tdi <= 1'b1; end // On the last bit, set TMS to '1' if (((_bit == (nb_bits_in_this_byte - 1)) && (index == (length - 1))) && (flip_tms == 1)) begin tms <= 1'b1; end #TCK_HALF_PERIOD tck <= 1; data_in[_bit] <= tdo; #TCK_HALF_PERIOD tck <= 0; end buffer_in[index] = data_in; end tdi <= 1'b0; tms <= 1'b0; end endtask endmodule