{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "91a2a2bd",
      "metadata": {},
      "source": [
        "### License\n",
        "Copyright (C) 2021-2022, Xilinx, Inc.\n",
        "<br>\n",
        "Copyright (C) 2022-2024, Advanced Micro Devices, Inc.\n",
        "<p>\n",
        "Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "you may not use this file except in compliance with the License.\n",
        "<p>\n",
        "You may obtain a copy of the License at <a href=\"http://www.apache.org/licenses/LICENSE-2.0\"?>http://www.apache.org/licenses/LICENSE-2.0</a><br><br>\n",
        "Unless required by applicable law or agreed to in writing, software\n",
        "distributed under the License is distributed on an \"AS IS\" BASIS, \n",
        "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "See the License for the specific language governing permissions and\n",
        "limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "50eede15",
      "metadata": {},
      "source": [
        "# ChipScoPy JTAG Access Example\n",
        "\n",
        "\n",
        "<img src=\"../img/api_overview.png\" width=\"500\" align=\"left\">"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a1a3e658",
      "metadata": {},
      "source": [
        "## Description\n",
        "This demo shows how to perform JTAG operations on cables or devices in scan chain using the ChipScoPy Python API.\n",
        "\n",
        "\n",
        "## Requirements\n",
        "- Local or remote Xilinx Versal board, such as a VCK190\n",
        "- Xilinx hw_server 2024.1 or greater\n",
        "- Python 3.8 or greater installed\n",
        "- ChipScoPy 2024.1 or greater installed\n",
        "- Jupyter notebook support installed - Please do so, using the command `pip install chipscopy[jupyter]`"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "af922025",
      "metadata": {},
      "source": [
        "## 1 - Initialization: Imports and File Paths\n",
        "\n",
        "After this step,\n",
        "- Required functions and classes are imported\n",
        "- Paths to server(s) and files are set correctly"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "bb10a295",
      "metadata": {},
      "outputs": [],
      "source": [
        "import os\n",
        "import sys\n",
        "\n",
        "from chipscopy import create_session, report_versions, delete_session\n",
        "from chipscopy.api.jtag import JtagState, JtagSequence"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "f88ca4b3",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "HW_URL=TCP:localhost:3121\n"
          ]
        }
      ],
      "source": [
        "# Make sure to start the hw_server prior to running.\n",
        "# Specify location of the running hw_server below.\n",
        "# The default is localhost - but can be other locations on the network.\n",
        "HW_URL = os.getenv(\"HW_SERVER_URL\", \"TCP:localhost:3121\")\n",
        "print(f\"HW_URL={HW_URL}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "29e5ba65",
      "metadata": {},
      "source": [
        "## 2 - Create a session and connect to the hw_server\n",
        "\n",
        "The session is a container that keeps track of devices and debug cores.\n",
        "After this step,\n",
        "- Session is initialized and connected to `hw_server`\n",
        "- Versions are detected and reported to stdout\n",
        "\n",
        "*NOTE*: No `cs_server` is required for this example."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "1a5dfbd5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
              "\n",
              "</pre>\n"
            ],
            "text/plain": [
              "\n",
              "\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-style: italic\">                      ChipScoPy Version Information                      </span>\n",
              "┌────────────────────────────┬──────────────────────────────────────────┐\n",
              "│<span style=\"font-weight: bold\">                     Entity </span>│<span style=\"font-weight: bold\"> Version                                  </span>│\n",
              "├────────────────────────────┼──────────────────────────────────────────┤\n",
              "│                  ChipScoPy │ ┌───────────┬──────────────────────┐     │\n",
              "│                            │ │<span style=\"font-weight: bold\"> Attribute </span>│<span style=\"font-weight: bold\"> Value                </span>│     │\n",
              "│                            │ ├───────────┼──────────────────────┤     │\n",
              "│                            │ │     Build │ 2024.1.1717606426    │     │\n",
              "│                            │ │ Timestamp │ Jun 05 2024-09:53:46 │     │\n",
              "│                            │ └───────────┴──────────────────────┘     │\n",
              "│                            │                                          │\n",
              "│ hw_server @ localhost:3121 │ ┌───────────┬──────────────────────────┐ │\n",
              "│                            │ │<span style=\"font-weight: bold\"> Attribute </span>│<span style=\"font-weight: bold\"> Value                    </span>│ │\n",
              "│                            │ ├───────────┼──────────────────────────┤ │\n",
              "│                            │ │    Status │ Connected                │ │\n",
              "│                            │ │     Build │ 1716424495               │ │\n",
              "│                            │ │   Version │ 2024.1                   │ │\n",
              "│                            │ │ Timestamp │ Wed May 22 18:34:55 2024 │ │\n",
              "│                            │ └───────────┴──────────────────────────┘ │\n",
              "└────────────────────────────┴──────────────────────────────────────────┘\n",
              "</pre>\n"
            ],
            "text/plain": [
              "\u001b[3m                      ChipScoPy Version Information                      \u001b[0m\n",
              "┌────────────────────────────┬──────────────────────────────────────────┐\n",
              "│\u001b[1m \u001b[0m\u001b[1m                    Entity\u001b[0m\u001b[1m \u001b[0m│\u001b[1m \u001b[0m\u001b[1mVersion                                 \u001b[0m\u001b[1m \u001b[0m│\n",
              "├────────────────────────────┼──────────────────────────────────────────┤\n",
              "│                  ChipScoPy │ ┌───────────┬──────────────────────┐     │\n",
              "│                            │ │\u001b[1m \u001b[0m\u001b[1mAttribute\u001b[0m\u001b[1m \u001b[0m│\u001b[1m \u001b[0m\u001b[1mValue               \u001b[0m\u001b[1m \u001b[0m│     │\n",
              "│                            │ ├───────────┼──────────────────────┤     │\n",
              "│                            │ │     Build │ 2024.1.1717606426    │     │\n",
              "│                            │ │ Timestamp │ Jun 05 2024-09:53:46 │     │\n",
              "│                            │ └───────────┴──────────────────────┘     │\n",
              "│                            │                                          │\n",
              "│ hw_server @ localhost:3121 │ ┌───────────┬──────────────────────────┐ │\n",
              "│                            │ │\u001b[1m \u001b[0m\u001b[1mAttribute\u001b[0m\u001b[1m \u001b[0m│\u001b[1m \u001b[0m\u001b[1mValue                   \u001b[0m\u001b[1m \u001b[0m│ │\n",
              "│                            │ ├───────────┼──────────────────────────┤ │\n",
              "│                            │ │    Status │ Connected                │ │\n",
              "│                            │ │     Build │ 1716424495               │ │\n",
              "│                            │ │   Version │ 2024.1                   │ │\n",
              "│                            │ │ Timestamp │ Wed May 22 18:34:55 2024 │ │\n",
              "│                            │ └───────────┴──────────────────────────┘ │\n",
              "└────────────────────────────┴──────────────────────────────────────────┘\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
              "\n",
              "</pre>\n"
            ],
            "text/plain": [
              "\n",
              "\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "session = create_session(hw_server_url=HW_URL)\n",
        "report_versions(session)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6e8cf205",
      "metadata": {},
      "source": [
        "   ## 3 - JTAG Cable Class\n",
        "   \n",
        "   The JTAG cable class allows operations to run against the whole scan chain. This example finds the first cable in the scan chain and locks the cable to ensure exclusive access."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "ab9ec42e",
      "metadata": {},
      "outputs": [],
      "source": [
        "jtag_cables = session.jtag_cables\n",
        "\n",
        "# Lock JTAG cable. This prevents other clients from performing any JTAG shifts or state changes on \n",
        "# the scan chain.\n",
        "jtag_cables[0].lock()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a98676f8",
      "metadata": {},
      "source": [
        "## 4 - JTAG Sequence\n",
        "\n",
        "A jtag sequence represents a set of operations to perform. This sequence object holds a reference to the cable object upon which the sequence will be run. Multiple commands may be appended to the sequence."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "698f5eab",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Create JTAG sequence object\n",
        "seq = JtagSequence(jtag_cables[0])\n",
        "\n",
        "# Add command to move JTAG state machine to TEST-LOGIC-RESET state and then generate 5 JTAG clocks\n",
        "seq.set_state(JtagState.RESET, 5)\n",
        "\n",
        "# Add command to shift 256-bit data in DRSHIFT state\n",
        "seq.dr_shift(\n",
        "    data=0x000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F,\n",
        "    size=256,\n",
        "    capture=True,\n",
        "    end_state=JtagState.IDLE,\n",
        ")\n",
        "\n",
        "# Add command to shift data in DRSHIFT state. JTAG TDI signal will be set to 1 for 70 clocks (bits)\n",
        "seq.dr_shift(tdi=1, size=70, capture=True, end_state=JtagState.IDLE)\n",
        "\n",
        "shift_data_size = 16\n",
        "shift_data = 0x101112131415161718191A1B1C1D1E1F .to_bytes(shift_data_size, sys.byteorder)\n",
        "# Add command to shift data in DRSHIFT state. In this case data is 16 bytes in bytearray format.\n",
        "seq.dr_shift(\n",
        "    data=bytearray(shift_data), size=shift_data_size * 8, capture=True, end_state=JtagState.IDLE\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3860e7fd",
      "metadata": {},
      "source": [
        "   ## 5 - Run sequence and print results"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "8d2b7f65",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Result of operations in JTAG sequence -  ['0x8090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f6ba0047714ca8093', '0x3f6ba0047714ca8093', '0x18191a1b1c1d1e1f6ba0047714ca8093']\n"
          ]
        }
      ],
      "source": [
        "# Run JTAG commands added in the sequence object\n",
        "seq_results = seq.run()\n",
        "\n",
        "# Convert JTAG sequence result from bytearray to hexadecimal format\n",
        "hex_result = [\n",
        "    hex(int.from_bytes(seq_results[i], sys.byteorder)) for i in range(0, len(seq_results))\n",
        "]\n",
        "print(\"Result of operations in JTAG sequence - \", hex_result)\n",
        "# Unlock the locked JTAG device\n",
        "jtag_cables[0].unlock()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "366df603",
      "metadata": {},
      "source": [
        "   ## Step 6 - JTAG Device Class\n",
        "\n",
        "JTAG operations can also be performed on individual devices in the scan chain instead of above example of performing JTAG operations on a JTAG cable (whole scan chain). This is a convenience class to target a specific device."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "73e3288a",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Result of operations in JTAG sequence -  ['0xffffffffffffffff35d0023b8a654049']\n"
          ]
        }
      ],
      "source": [
        "# Get devices on JTAG chain\n",
        "jtag_devices = session.jtag_devices\n",
        "\n",
        "# Lock first JTAG device. This prevents other clients from performing any JTAG shifts or state changes on the scan\n",
        "# chain.\n",
        "jtag_devices[0].lock()\n",
        "\n",
        "# Create JTAG sequence object\n",
        "seq = JtagSequence(jtag_devices[0])\n",
        "\n",
        "# Add command to move JTAG state machine to TEST-LOGIC-RESET state and then generate 10 JTAG clocks\n",
        "seq.set_state(JtagState.RESET, 10)\n",
        "\n",
        "# Add command to shift 128-bit data in DRSHIFT state\n",
        "seq.dr_shift(\n",
        "    data=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, size=128, capture=True, end_state=JtagState.IDLE\n",
        ")\n",
        "\n",
        "# Run JTAG commands added in the sequence object\n",
        "seq_results = seq.run()\n",
        "\n",
        "# Unlock the locked JTAG device\n",
        "jtag_devices[0].unlock()\n",
        "\n",
        "# Clear JTAG commands in sequence object. After clear, this object can be reused for new set of JTAG operations\n",
        "seq.clear()\n",
        "\n",
        "# Convert JTAG sequence result from bytearray to hexadecimal format\n",
        "hex_result = [\n",
        "    hex(int.from_bytes(seq_results[i], sys.byteorder)) for i in range(0, len(seq_results))\n",
        "]\n",
        "print(\"Result of operations in JTAG sequence - \", hex_result)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "05335631",
      "metadata": {},
      "outputs": [],
      "source": [
        "## When done with testing, close the connection\n",
        "delete_session(session)"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "venv",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.11.2"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
