get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/89165/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 89165,
    "url": "https://patches.dpdk.org/api/patches/89165/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20210315224837.18619-1-cristian.dumitrescu@intel.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20210315224837.18619-1-cristian.dumitrescu@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210315224837.18619-1-cristian.dumitrescu@intel.com",
    "date": "2021-03-15T22:48:36",
    "name": "[v4,1/2] pipeline: add register array support to SWX pipeline",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "00c02212f30a15b0da9e381904938a8b514f8467",
    "submitter": {
        "id": 19,
        "url": "https://patches.dpdk.org/api/people/19/?format=api",
        "name": "Cristian Dumitrescu",
        "email": "cristian.dumitrescu@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20210315224837.18619-1-cristian.dumitrescu@intel.com/mbox/",
    "series": [
        {
            "id": 15672,
            "url": "https://patches.dpdk.org/api/series/15672/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=15672",
            "date": "2021-03-15T22:48:36",
            "name": "[v4,1/2] pipeline: add register array support to SWX pipeline",
            "version": 4,
            "mbox": "https://patches.dpdk.org/series/15672/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/89165/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/89165/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id B27EBA054F;\n\tMon, 15 Mar 2021 23:48:45 +0100 (CET)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 717D14068C;\n\tMon, 15 Mar 2021 23:48:44 +0100 (CET)",
            "from mga04.intel.com (mga04.intel.com [192.55.52.120])\n by mails.dpdk.org (Postfix) with ESMTP id 4B8DC4068B\n for <dev@dpdk.org>; Mon, 15 Mar 2021 23:48:41 +0100 (CET)",
            "from fmsmga004.fm.intel.com ([10.253.24.48])\n by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 15 Mar 2021 15:48:40 -0700",
            "from silpixa00400573.ir.intel.com (HELO\n silpixa00400573.ger.corp.intel.com) ([10.237.223.107])\n by fmsmga004.fm.intel.com with ESMTP; 15 Mar 2021 15:48:38 -0700"
        ],
        "IronPort-SDR": [
            "\n KTn1ne0qqWWV1n58hgN6BETSZE3CB96etONQkUOkD8rR1jSzzmjT3tDiXe0WTCFDNmP0/AQnuF\n KCcL4aFmj2wg==",
            "\n cS2KkW+nprDL6PZmeiEDKZaIzih5x6cQTnB7pl6qi5UiRuXh/SdlXFQXR9yY0pf0sFR/wnLrsz\n ZicLHa7Rs5SA=="
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6000,8403,9924\"; a=\"186786962\"",
            "E=Sophos;i=\"5.81,251,1610438400\"; d=\"scan'208\";a=\"186786962\"",
            "E=Sophos;i=\"5.81,251,1610438400\"; d=\"scan'208\";a=\"432811225\""
        ],
        "X-ExtLoop1": "1",
        "From": "Cristian Dumitrescu <cristian.dumitrescu@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Mon, 15 Mar 2021 22:48:36 +0000",
        "Message-Id": "<20210315224837.18619-1-cristian.dumitrescu@intel.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20210315222204.17689-1-cristian.dumitrescu@intel.com>",
        "References": "<20210315222204.17689-1-cristian.dumitrescu@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v4 1/2] pipeline: add register array support to\n SWX pipeline",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Register arrays are stateful objects that can be read & modified by\nboth the data plane and the control plane, as opposed to tables, which\nare read-only for data plane. One key use-case is the implementation\nof stats counters.\n\nSigned-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>\n---\n examples/pipeline/cli.c                     |  125 ++\n examples/pipeline/examples/registers.cli    |   28 +\n examples/pipeline/examples/registers.spec   |   67 +\n lib/librte_pipeline/rte_swx_ctl.h           |   79 +\n lib/librte_pipeline/rte_swx_pipeline.c      | 1602 +++++++++++++++++--\n lib/librte_pipeline/rte_swx_pipeline.h      |   24 +\n lib/librte_pipeline/rte_swx_pipeline_spec.c |  105 ++\n lib/librte_pipeline/version.map             |    6 +\n 8 files changed, 1882 insertions(+), 154 deletions(-)\n create mode 100644 examples/pipeline/examples/registers.cli\n create mode 100644 examples/pipeline/examples/registers.spec",
    "diff": "diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c\nindex 30c2dd34d..cdf8f13f3 100644\n--- a/examples/pipeline/cli.c\n+++ b/examples/pipeline/cli.c\n@@ -1009,6 +1009,105 @@ cmd_pipeline_table_update(char **tokens,\n \t\tfclose(file_default);\n }\n \n+static const char cmd_pipeline_regrd_help[] =\n+\"pipeline <pipeline_name> regrd <register_array_name> <index>\\n\";\n+\n+static void\n+cmd_pipeline_regrd(char **tokens,\n+\tuint32_t n_tokens,\n+\tchar *out,\n+\tsize_t out_size,\n+\tvoid *obj)\n+{\n+\tstruct pipeline *p;\n+\tconst char *name;\n+\tuint64_t value;\n+\tuint32_t idx;\n+\tint status;\n+\n+\tif (n_tokens != 5) {\n+\t\tsnprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);\n+\t\treturn;\n+\t}\n+\n+\tp = pipeline_find(obj, tokens[1]);\n+\tif (!p || !p->ctl) {\n+\t\tsnprintf(out, out_size, MSG_ARG_INVALID, \"pipeline_name\");\n+\t\treturn;\n+\t}\n+\n+\tif (strcmp(tokens[2], \"regrd\")) {\n+\t\tsnprintf(out, out_size, MSG_ARG_NOT_FOUND, \"regrd\");\n+\t\treturn;\n+\t}\n+\n+\tname = tokens[3];\n+\n+\tif (parser_read_uint32(&idx, tokens[4])) {\n+\t\tsnprintf(out, out_size, MSG_ARG_INVALID, \"index\");\n+\t\treturn;\n+\t}\n+\n+\tstatus = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value);\n+\tif (status) {\n+\t\tsnprintf(out, out_size, \"Command failed.\\n\");\n+\t\treturn;\n+\t}\n+\n+\tsnprintf(out, out_size, \"0x%\" PRIx64 \"\\n\", value);\n+}\n+\n+static const char cmd_pipeline_regwr_help[] =\n+\"pipeline <pipeline_name> regwr <register_array_name> <index> <value>\\n\";\n+\n+static void\n+cmd_pipeline_regwr(char **tokens,\n+\tuint32_t n_tokens,\n+\tchar *out,\n+\tsize_t out_size,\n+\tvoid *obj)\n+{\n+\tstruct pipeline *p;\n+\tconst char *name;\n+\tuint64_t value;\n+\tuint32_t idx;\n+\tint status;\n+\n+\tif (n_tokens != 6) {\n+\t\tsnprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);\n+\t\treturn;\n+\t}\n+\n+\tp = pipeline_find(obj, tokens[1]);\n+\tif (!p || !p->ctl) {\n+\t\tsnprintf(out, out_size, MSG_ARG_INVALID, \"pipeline_name\");\n+\t\treturn;\n+\t}\n+\n+\tif (strcmp(tokens[2], \"regwr\")) {\n+\t\tsnprintf(out, out_size, MSG_ARG_NOT_FOUND, \"regwr\");\n+\t\treturn;\n+\t}\n+\n+\tname = tokens[3];\n+\n+\tif (parser_read_uint32(&idx, tokens[4])) {\n+\t\tsnprintf(out, out_size, MSG_ARG_INVALID, \"index\");\n+\t\treturn;\n+\t}\n+\n+\tif (parser_read_uint64(&value, tokens[5])) {\n+\t\tsnprintf(out, out_size, MSG_ARG_INVALID, \"value\");\n+\t\treturn;\n+\t}\n+\n+\tstatus = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value);\n+\tif (status) {\n+\t\tsnprintf(out, out_size, \"Command failed.\\n\");\n+\t\treturn;\n+\t}\n+}\n+\n static const char cmd_pipeline_stats_help[] =\n \"pipeline <pipeline_name> stats\\n\";\n \n@@ -1202,6 +1301,8 @@ cmd_help(char **tokens,\n \t\t\t\"\\tpipeline port out\\n\"\n \t\t\t\"\\tpipeline build\\n\"\n \t\t\t\"\\tpipeline table update\\n\"\n+\t\t\t\"\\tpipeline regrd\\n\"\n+\t\t\t\"\\tpipeline regwr\\n\"\n \t\t\t\"\\tpipeline stats\\n\"\n \t\t\t\"\\tthread pipeline enable\\n\"\n \t\t\t\"\\tthread pipeline disable\\n\\n\");\n@@ -1254,6 +1355,18 @@ cmd_help(char **tokens,\n \t\treturn;\n \t}\n \n+\tif ((strcmp(tokens[0], \"pipeline\") == 0) &&\n+\t\t(n_tokens == 2) && (strcmp(tokens[1], \"regrd\") == 0)) {\n+\t\tsnprintf(out, out_size, \"\\n%s\\n\", cmd_pipeline_regrd_help);\n+\t\treturn;\n+\t}\n+\n+\tif ((strcmp(tokens[0], \"pipeline\") == 0) &&\n+\t\t(n_tokens == 2) && (strcmp(tokens[1], \"regwr\") == 0)) {\n+\t\tsnprintf(out, out_size, \"\\n%s\\n\", cmd_pipeline_regwr_help);\n+\t\treturn;\n+\t}\n+\n \tif ((strcmp(tokens[0], \"pipeline\") == 0) &&\n \t\t(n_tokens == 2) && (strcmp(tokens[1], \"stats\") == 0)) {\n \t\tsnprintf(out, out_size, \"\\n%s\\n\", cmd_pipeline_stats_help);\n@@ -1356,6 +1469,18 @@ cli_process(char *in, char *out, size_t out_size, void *obj)\n \t\t\treturn;\n \t\t}\n \n+\t\tif ((n_tokens >= 3) &&\n+\t\t\t(strcmp(tokens[2], \"regrd\") == 0)) {\n+\t\t\tcmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj);\n+\t\t\treturn;\n+\t\t}\n+\n+\t\tif ((n_tokens >= 3) &&\n+\t\t\t(strcmp(tokens[2], \"regwr\") == 0)) {\n+\t\t\tcmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj);\n+\t\t\treturn;\n+\t\t}\n+\n \t\tif ((n_tokens >= 3) &&\n \t\t\t(strcmp(tokens[2], \"stats\") == 0)) {\n \t\t\tcmd_pipeline_stats(tokens, n_tokens, out, out_size,\ndiff --git a/examples/pipeline/examples/registers.cli b/examples/pipeline/examples/registers.cli\nnew file mode 100644\nindex 000000000..8d026294c\n--- /dev/null\n+++ b/examples/pipeline/examples/registers.cli\n@@ -0,0 +1,28 @@\n+; SPDX-License-Identifier: BSD-3-Clause\n+; Copyright(c) 2020 Intel Corporation\n+\n+; Example command line:\n+;\t./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/registers.cli\n+\n+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0\n+\n+link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on\n+link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on\n+link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on\n+link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on\n+\n+pipeline PIPELINE0 create 0\n+\n+pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32\n+pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32\n+pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32\n+pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32\n+\n+pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32\n+pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32\n+pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32\n+pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32\n+\n+pipeline PIPELINE0 build ./examples/pipeline/examples/registers.spec\n+\n+thread 1 pipeline PIPELINE0 enable\ndiff --git a/examples/pipeline/examples/registers.spec b/examples/pipeline/examples/registers.spec\nnew file mode 100644\nindex 000000000..74a014ad0\n--- /dev/null\n+++ b/examples/pipeline/examples/registers.spec\n@@ -0,0 +1,67 @@\n+; SPDX-License-Identifier: BSD-3-Clause\n+; Copyright(c) 2021 Intel Corporation\n+\n+; This program is setting up two register arrays called \"pkt_counters\" and \"byte_counters\".\n+; On every input packet (Ethernet/IPv4), the \"pkt_counters\" register at location indexed by\n+; the IPv4 header \"Source Address\" field is incremented, while the same location in the\n+; \"byte_counters\" array accummulates the value of the IPv4 header \"Total Length\" field.\n+;\n+; The \"regrd\" and \"regwr\" CLI commands can be used to read and write the current value of\n+; any register array location.\n+\n+//\n+// Headers.\n+//\n+struct ethernet_h {\n+\tbit<48> dst_addr\n+\tbit<48> src_addr\n+\tbit<16> ethertype\n+}\n+\n+struct ipv4_h {\n+\tbit<8> ver_ihl\n+\tbit<8> diffserv\n+\tbit<16> total_len\n+\tbit<16> identification\n+\tbit<16> flags_offset\n+\tbit<8> ttl\n+\tbit<8> protocol\n+\tbit<16> hdr_checksum\n+\tbit<32> src_addr\n+\tbit<32> dst_addr\n+}\n+\n+header ethernet instanceof ethernet_h\n+header ipv4 instanceof ipv4_h\n+\n+//\n+// Meta-data.\n+//\n+struct metadata_t {\n+\tbit<32> port_in\n+\tbit<32> port_out\n+}\n+\n+metadata instanceof metadata_t\n+\n+//\n+// Registers.\n+//\n+regarray pkt_counters size 65536 initval 0\n+regarray byte_counters size 65536 initval 0\n+\n+//\n+// Pipeline.\n+//\n+apply {\n+\trx m.port_in\n+\textract h.ethernet\n+\textract h.ipv4\n+\tregadd pkt_counters h.ipv4.src_addr 1\n+\tregadd byte_counters h.ipv4.src_addr h.ipv4.total_len\n+\tmov m.port_out m.port_in\n+\txor m.port_out 1\n+\temit h.ethernet\n+\temit h.ipv4\n+\ttx m.port_out\n+}\ndiff --git a/lib/librte_pipeline/rte_swx_ctl.h b/lib/librte_pipeline/rte_swx_ctl.h\nindex 530671db1..c0a55c6f0 100644\n--- a/lib/librte_pipeline/rte_swx_ctl.h\n+++ b/lib/librte_pipeline/rte_swx_ctl.h\n@@ -46,6 +46,9 @@ struct rte_swx_ctl_pipeline_info {\n \n \t/** Number of tables. */\n \tuint32_t n_tables;\n+\n+\t/** Number of register arrays. */\n+\tuint32_t n_regarrays;\n };\n \n /**\n@@ -557,6 +560,82 @@ rte_swx_ctl_pipeline_table_fprintf(FILE *f,\n \t\t\t\t   struct rte_swx_ctl_pipeline *ctl,\n \t\t\t\t   const char *table_name);\n \n+/*\n+ * Register Array Query API.\n+ */\n+\n+/** Register array info. */\n+struct rte_swx_ctl_regarray_info {\n+\t/** Register array name. */\n+\tchar name[RTE_SWX_CTL_NAME_SIZE];\n+\n+\t/** Register array size. */\n+\tuint32_t size;\n+};\n+\n+/**\n+ * Register array info get\n+ *\n+ * @param[in] p\n+ *   Pipeline handle.\n+ * @param[in] regarray_id\n+ *   Register array ID (0 .. *n_regarrays* - 1).\n+ * @param[out] regarray\n+ *   Register array info.\n+ * @return\n+ *   0 on success or the following error codes otherwise:\n+ *   -EINVAL: Invalid argument.\n+ */\n+__rte_experimental\n+int\n+rte_swx_ctl_regarray_info_get(struct rte_swx_pipeline *p,\n+\t\t\t      uint32_t regarray_id,\n+\t\t\t      struct rte_swx_ctl_regarray_info *regarray);\n+\n+/**\n+ * Register read\n+ *\n+ * @param[in] p\n+ *   Pipeline handle.\n+ * @param[in] regarray_name\n+ *   Register array name.\n+ * @param[in] regarray_index\n+ *   Register index within the array (0 .. *size* - 1).\n+ * @param[out] value\n+ *   Current register value.\n+ * @return\n+ *   0 on success or the following error codes otherwise:\n+ *   -EINVAL: Invalid argument.\n+ */\n+__rte_experimental\n+int\n+rte_swx_ctl_pipeline_regarray_read(struct rte_swx_pipeline *p,\n+\t\t\t\t   const char *regarray_name,\n+\t\t\t\t   uint32_t regarray_index,\n+\t\t\t\t   uint64_t *value);\n+\n+/**\n+ * Register write\n+ *\n+ * @param[in] p\n+ *   Pipeline handle.\n+ * @param[in] regarray_name\n+ *   Register array name.\n+ * @param[in] regarray_index\n+ *   Register index within the array (0 .. *size* - 1).\n+ * @param[in] value\n+ *   Value to be written to the register.\n+ * @return\n+ *   0 on success or the following error codes otherwise:\n+ *   -EINVAL: Invalid argument.\n+ */\n+__rte_experimental\n+int\n+rte_swx_ctl_pipeline_regarray_write(struct rte_swx_pipeline *p,\n+\t\t\t\t   const char *regarray_name,\n+\t\t\t\t   uint32_t regarray_index,\n+\t\t\t\t   uint64_t value);\n+\n /**\n  * Pipeline control free\n  *\ndiff --git a/lib/librte_pipeline/rte_swx_pipeline.c b/lib/librte_pipeline/rte_swx_pipeline.c\nindex eaaed7a0a..5be87ca4f 100644\n--- a/lib/librte_pipeline/rte_swx_pipeline.c\n+++ b/lib/librte_pipeline/rte_swx_pipeline.c\n@@ -45,9 +45,59 @@ do {                                                                           \\\n #define TRACE(...)\n #endif\n \n+/*\n+ * Environment.\n+ */\n #define ntoh64(x) rte_be_to_cpu_64(x)\n #define hton64(x) rte_cpu_to_be_64(x)\n \n+#ifndef RTE_SWX_PIPELINE_HUGE_PAGES_DISABLE\n+\n+#include <rte_malloc.h>\n+\n+static void *\n+env_malloc(size_t size, size_t alignment, int numa_node)\n+{\n+\treturn rte_zmalloc_socket(NULL, size, alignment, numa_node);\n+}\n+\n+static void\n+env_free(void *start, size_t size __rte_unused)\n+{\n+\trte_free(start);\n+}\n+\n+#else\n+\n+#include <numa.h>\n+\n+static void *\n+env_malloc(size_t size, size_t alignment __rte_unused, int numa_node)\n+{\n+\tvoid *start;\n+\n+\tif (numa_available() == -1)\n+\t\treturn NULL;\n+\n+\tstart = numa_alloc_onnode(size, numa_node);\n+\tif (!start)\n+\t\treturn NULL;\n+\n+\tmemset(start, 0, size);\n+\treturn start;\n+}\n+\n+static void\n+env_free(void *start, size_t size)\n+{\n+\tif (numa_available() == -1)\n+\t\treturn;\n+\n+\tnuma_free(start, size);\n+}\n+\n+#endif\n+\n /*\n  * Struct.\n  */\n@@ -361,6 +411,53 @@ enum instruction_type {\n \tINSTR_ALU_SHR_MI, /* dst = MEF, src = I */\n \tINSTR_ALU_SHR_HI, /* dst = H, src = I */\n \n+\t/* regprefetch REGARRAY index\n+\t * prefetch REGARRAY[index]\n+\t * index = HMEFTI\n+\t */\n+\tINSTR_REGPREFETCH_RH, /* index = H */\n+\tINSTR_REGPREFETCH_RM, /* index = MEFT */\n+\tINSTR_REGPREFETCH_RI, /* index = I */\n+\n+\t/* regrd dst REGARRAY index\n+\t * dst = REGARRAY[index]\n+\t * dst = HMEF, index = HMEFTI\n+\t */\n+\tINSTR_REGRD_HRH, /* dst = H, index = H */\n+\tINSTR_REGRD_HRM, /* dst = H, index = MEFT */\n+\tINSTR_REGRD_HRI, /* dst = H, index = I */\n+\tINSTR_REGRD_MRH, /* dst = MEF, index = H */\n+\tINSTR_REGRD_MRM, /* dst = MEF, index = MEFT */\n+\tINSTR_REGRD_MRI, /* dst = MEF, index = I */\n+\n+\t/* regwr REGARRAY index src\n+\t * REGARRAY[index] = src\n+\t * index = HMEFTI, src = HMEFTI\n+\t */\n+\tINSTR_REGWR_RHH, /* index = H, src = H */\n+\tINSTR_REGWR_RHM, /* index = H, src = MEFT */\n+\tINSTR_REGWR_RHI, /* index = H, src = I */\n+\tINSTR_REGWR_RMH, /* index = MEFT, src = H */\n+\tINSTR_REGWR_RMM, /* index = MEFT, src = MEFT */\n+\tINSTR_REGWR_RMI, /* index = MEFT, src = I */\n+\tINSTR_REGWR_RIH, /* index = I, src = H */\n+\tINSTR_REGWR_RIM, /* index = I, src = MEFT */\n+\tINSTR_REGWR_RII, /* index = I, src = I */\n+\n+\t/* regadd REGARRAY index src\n+\t * REGARRAY[index] += src\n+\t * index = HMEFTI, src = HMEFTI\n+\t */\n+\tINSTR_REGADD_RHH, /* index = H, src = H */\n+\tINSTR_REGADD_RHM, /* index = H, src = MEFT */\n+\tINSTR_REGADD_RHI, /* index = H, src = I */\n+\tINSTR_REGADD_RMH, /* index = MEFT, src = H */\n+\tINSTR_REGADD_RMM, /* index = MEFT, src = MEFT */\n+\tINSTR_REGADD_RMI, /* index = MEFT, src = I */\n+\tINSTR_REGADD_RIH, /* index = I, src = H */\n+\tINSTR_REGADD_RIM, /* index = I, src = MEFT */\n+\tINSTR_REGADD_RII, /* index = I, src = I */\n+\n \t/* table TABLE */\n \tINSTR_TABLE,\n \n@@ -495,6 +592,21 @@ struct instr_dst_src {\n \t};\n };\n \n+struct instr_regarray {\n+\tuint8_t regarray_id;\n+\tuint8_t pad[3];\n+\n+\tunion {\n+\t\tstruct instr_operand idx;\n+\t\tuint32_t idx_val;\n+\t};\n+\n+\tunion {\n+\t\tstruct instr_operand dstsrc;\n+\t\tuint64_t dstsrc_val;\n+\t};\n+};\n+\n struct instr_dma {\n \tstruct {\n \t\tuint8_t header_id[8];\n@@ -529,6 +641,7 @@ struct instruction {\n \t\tstruct instr_io io;\n \t\tstruct instr_hdr_validity valid;\n \t\tstruct instr_dst_src mov;\n+\t\tstruct instr_regarray regarray;\n \t\tstruct instr_dma dma;\n \t\tstruct instr_dst_src alu;\n \t\tstruct instr_table table;\n@@ -608,6 +721,24 @@ struct table_runtime {\n \tuint8_t **key;\n };\n \n+/*\n+ * Register array.\n+ */\n+struct regarray {\n+\tTAILQ_ENTRY(regarray) node;\n+\tchar name[RTE_SWX_NAME_SIZE];\n+\tuint64_t init_val;\n+\tuint32_t size;\n+\tuint32_t id;\n+};\n+\n+TAILQ_HEAD(regarray_tailq, regarray);\n+\n+struct regarray_runtime {\n+\tuint64_t *regarray;\n+\tuint32_t size_mask;\n+};\n+\n /*\n  * Pipeline.\n  */\n@@ -983,11 +1114,13 @@ struct rte_swx_pipeline {\n \tstruct action_tailq actions;\n \tstruct table_type_tailq table_types;\n \tstruct table_tailq tables;\n+\tstruct regarray_tailq regarrays;\n \n \tstruct port_in_runtime *in;\n \tstruct port_out_runtime *out;\n \tstruct instruction **action_instructions;\n \tstruct rte_swx_table_state *table_state;\n+\tstruct regarray_runtime *regarray_runtime;\n \tstruct instruction *instructions;\n \tstruct thread threads[RTE_SWX_PIPELINE_THREADS_MAX];\n \n@@ -998,6 +1131,7 @@ struct rte_swx_pipeline {\n \tuint32_t n_extern_funcs;\n \tuint32_t n_actions;\n \tuint32_t n_tables;\n+\tuint32_t n_regarrays;\n \tuint32_t n_headers;\n \tuint32_t thread_id;\n \tuint32_t port_id;\n@@ -4622,222 +4756,1124 @@ instr_alu_ckadd_struct_exec(struct rte_swx_pipeline *p)\n }\n \n /*\n- * jmp.\n+ * Register array.\n  */\n-static struct action *\n-action_find(struct rte_swx_pipeline *p, const char *name);\n-\n-static int\n-instr_jmp_translate(struct rte_swx_pipeline *p __rte_unused,\n-\t\t    struct action *action __rte_unused,\n-\t\t    char **tokens,\n-\t\t    int n_tokens,\n-\t\t    struct instruction *instr,\n-\t\t    struct instruction_data *data)\n-{\n-\tCHECK(n_tokens == 2, EINVAL);\n-\n-\tstrcpy(data->jmp_label, tokens[1]);\n-\n-\tinstr->type = INSTR_JMP;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n-\treturn 0;\n-}\n+static struct regarray *\n+regarray_find(struct rte_swx_pipeline *p, const char *name);\n \n static int\n-instr_jmp_valid_translate(struct rte_swx_pipeline *p,\n-\t\t\t  struct action *action __rte_unused,\n-\t\t\t  char **tokens,\n-\t\t\t  int n_tokens,\n-\t\t\t  struct instruction *instr,\n-\t\t\t  struct instruction_data *data)\n+instr_regprefetch_translate(struct rte_swx_pipeline *p,\n+\t\t      struct action *action,\n+\t\t      char **tokens,\n+\t\t      int n_tokens,\n+\t\t      struct instruction *instr,\n+\t\t      struct instruction_data *data __rte_unused)\n {\n-\tstruct header *h;\n+\tchar *regarray = tokens[1], *idx = tokens[2];\n+\tstruct regarray *r;\n+\tstruct field *fidx;\n+\tuint32_t idx_struct_id, idx_val;\n \n \tCHECK(n_tokens == 3, EINVAL);\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+\tr = regarray_find(p, regarray);\n+\tCHECK(r, EINVAL);\n+\n+\t/* REGPREFETCH_RH, REGPREFETCH_RM. */\n+\tfidx = struct_field_parse(p, action, idx, &idx_struct_id);\n+\tif (fidx) {\n+\t\tinstr->type = INSTR_REGPREFETCH_RM;\n+\t\tif (idx[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGPREFETCH_RH;\n+\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx.struct_id = (uint8_t)idx_struct_id;\n+\t\tinstr->regarray.idx.n_bits = fidx->n_bits;\n+\t\tinstr->regarray.idx.offset = fidx->offset / 8;\n+\t\tinstr->regarray.dstsrc_val = 0; /* Unused. */\n+\t\treturn 0;\n+\t}\n \n-\th = header_parse(p, tokens[2]);\n-\tCHECK(h, EINVAL);\n+\t/* REGPREFETCH_RI. */\n+\tidx_val = strtoul(idx, &idx, 0);\n+\tCHECK(!idx[0], EINVAL);\n \n-\tinstr->type = INSTR_JMP_VALID;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n-\tinstr->jmp.header_id = h->id;\n+\tinstr->type = INSTR_REGPREFETCH_RI;\n+\tinstr->regarray.regarray_id = r->id;\n+\tinstr->regarray.idx_val = idx_val;\n+\tinstr->regarray.dstsrc_val = 0; /* Unused. */\n \treturn 0;\n }\n \n static int\n-instr_jmp_invalid_translate(struct rte_swx_pipeline *p,\n-\t\t\t    struct action *action __rte_unused,\n-\t\t\t    char **tokens,\n-\t\t\t    int n_tokens,\n-\t\t\t    struct instruction *instr,\n-\t\t\t    struct instruction_data *data)\n+instr_regrd_translate(struct rte_swx_pipeline *p,\n+\t\t      struct action *action,\n+\t\t      char **tokens,\n+\t\t      int n_tokens,\n+\t\t      struct instruction *instr,\n+\t\t      struct instruction_data *data __rte_unused)\n {\n-\tstruct header *h;\n+\tchar *dst = tokens[1], *regarray = tokens[2], *idx = tokens[3];\n+\tstruct regarray *r;\n+\tstruct field *fdst, *fidx;\n+\tuint32_t dst_struct_id, idx_struct_id, idx_val;\n \n-\tCHECK(n_tokens == 3, EINVAL);\n+\tCHECK(n_tokens == 4, EINVAL);\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+\tr = regarray_find(p, regarray);\n+\tCHECK(r, EINVAL);\n \n-\th = header_parse(p, tokens[2]);\n-\tCHECK(h, EINVAL);\n+\tfdst = struct_field_parse(p, NULL, dst, &dst_struct_id);\n+\tCHECK(fdst, EINVAL);\n \n-\tinstr->type = INSTR_JMP_INVALID;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n-\tinstr->jmp.header_id = h->id;\n-\treturn 0;\n-}\n+\t/* REGRD_HRH, REGRD_HRM, REGRD_MRH, REGRD_MRM. */\n+\tfidx = struct_field_parse(p, action, idx, &idx_struct_id);\n+\tif (fidx) {\n+\t\tinstr->type = INSTR_REGRD_MRM;\n+\t\tif (dst[0] == 'h' && idx[0] != 'h')\n+\t\t\tinstr->type = INSTR_REGRD_HRM;\n+\t\tif (dst[0] != 'h' && idx[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGRD_MRH;\n+\t\tif (dst[0] == 'h' && idx[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGRD_HRH;\n+\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx.struct_id = (uint8_t)idx_struct_id;\n+\t\tinstr->regarray.idx.n_bits = fidx->n_bits;\n+\t\tinstr->regarray.idx.offset = fidx->offset / 8;\n+\t\tinstr->regarray.dstsrc.struct_id = (uint8_t)dst_struct_id;\n+\t\tinstr->regarray.dstsrc.n_bits = fdst->n_bits;\n+\t\tinstr->regarray.dstsrc.offset = fdst->offset / 8;\n+\t\treturn 0;\n+\t}\n \n-static int\n-instr_jmp_hit_translate(struct rte_swx_pipeline *p __rte_unused,\n-\t\t\tstruct action *action,\n-\t\t\tchar **tokens,\n-\t\t\tint n_tokens,\n-\t\t\tstruct instruction *instr,\n-\t\t\tstruct instruction_data *data)\n-{\n-\tCHECK(!action, EINVAL);\n-\tCHECK(n_tokens == 2, EINVAL);\n+\t/* REGRD_MRI, REGRD_HRI. */\n+\tidx_val = strtoul(idx, &idx, 0);\n+\tCHECK(!idx[0], EINVAL);\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+\tinstr->type = INSTR_REGRD_MRI;\n+\tif (dst[0] == 'h')\n+\t\tinstr->type = INSTR_REGRD_HRI;\n \n-\tinstr->type = INSTR_JMP_HIT;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->regarray.regarray_id = r->id;\n+\tinstr->regarray.idx_val = idx_val;\n+\tinstr->regarray.dstsrc.struct_id = (uint8_t)dst_struct_id;\n+\tinstr->regarray.dstsrc.n_bits = fdst->n_bits;\n+\tinstr->regarray.dstsrc.offset = fdst->offset / 8;\n \treturn 0;\n }\n \n static int\n-instr_jmp_miss_translate(struct rte_swx_pipeline *p __rte_unused,\n-\t\t\t struct action *action,\n-\t\t\t char **tokens,\n-\t\t\t int n_tokens,\n-\t\t\t struct instruction *instr,\n-\t\t\t struct instruction_data *data)\n+instr_regwr_translate(struct rte_swx_pipeline *p,\n+\t\t      struct action *action,\n+\t\t      char **tokens,\n+\t\t      int n_tokens,\n+\t\t      struct instruction *instr,\n+\t\t      struct instruction_data *data __rte_unused)\n {\n-\tCHECK(!action, EINVAL);\n-\tCHECK(n_tokens == 2, EINVAL);\n+\tchar *regarray = tokens[1], *idx = tokens[2], *src = tokens[3];\n+\tstruct regarray *r;\n+\tstruct field *fidx, *fsrc;\n+\tuint64_t src_val;\n+\tuint32_t idx_struct_id, idx_val, src_struct_id;\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+\tCHECK(n_tokens == 4, EINVAL);\n \n-\tinstr->type = INSTR_JMP_MISS;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n-\treturn 0;\n-}\n+\tr = regarray_find(p, regarray);\n+\tCHECK(r, EINVAL);\n \n-static int\n-instr_jmp_action_hit_translate(struct rte_swx_pipeline *p,\n-\t\t\t       struct action *action,\n-\t\t\t       char **tokens,\n-\t\t\t       int n_tokens,\n-\t\t\t       struct instruction *instr,\n-\t\t\t       struct instruction_data *data)\n-{\n-\tstruct action *a;\n+\t/* REGWR_RHH, REGWR_RHM, REGWR_RMH, REGWR_RMM. */\n+\tfidx = struct_field_parse(p, action, idx, &idx_struct_id);\n+\tfsrc = struct_field_parse(p, action, src, &src_struct_id);\n+\tif (fidx && fsrc) {\n+\t\tinstr->type = INSTR_REGWR_RMM;\n+\t\tif (idx[0] == 'h' && src[0] != 'h')\n+\t\t\tinstr->type = INSTR_REGWR_RHM;\n+\t\tif (idx[0] != 'h' && src[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGWR_RMH;\n+\t\tif (idx[0] == 'h' && src[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGWR_RHH;\n+\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx.struct_id = (uint8_t)idx_struct_id;\n+\t\tinstr->regarray.idx.n_bits = fidx->n_bits;\n+\t\tinstr->regarray.idx.offset = fidx->offset / 8;\n+\t\tinstr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;\n+\t\tinstr->regarray.dstsrc.n_bits = fsrc->n_bits;\n+\t\tinstr->regarray.dstsrc.offset = fsrc->offset / 8;\n+\t\treturn 0;\n+\t}\n \n-\tCHECK(!action, EINVAL);\n-\tCHECK(n_tokens == 3, EINVAL);\n+\t/* REGWR_RHI, REGWR_RMI. */\n+\tif (fidx && !fsrc) {\n+\t\tsrc_val = strtoull(src, &src, 0);\n+\t\tCHECK(!src[0], EINVAL);\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+\t\tinstr->type = INSTR_REGWR_RMI;\n+\t\tif (idx[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGWR_RHI;\n \n-\ta = action_find(p, tokens[2]);\n-\tCHECK(a, EINVAL);\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx.struct_id = (uint8_t)idx_struct_id;\n+\t\tinstr->regarray.idx.n_bits = fidx->n_bits;\n+\t\tinstr->regarray.idx.offset = fidx->offset / 8;\n+\t\tinstr->regarray.dstsrc_val = src_val;\n+\t\treturn 0;\n+\t}\n \n-\tinstr->type = INSTR_JMP_ACTION_HIT;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n-\tinstr->jmp.action_id = a->id;\n-\treturn 0;\n-}\n+\t/* REGWR_RIH, REGWR_RIM. */\n+\tif (!fidx && fsrc) {\n+\t\tidx_val = strtoul(idx, &idx, 0);\n+\t\tCHECK(!idx[0], EINVAL);\n \n-static int\n-instr_jmp_action_miss_translate(struct rte_swx_pipeline *p,\n-\t\t\t\tstruct action *action,\n-\t\t\t\tchar **tokens,\n-\t\t\t\tint n_tokens,\n-\t\t\t\tstruct instruction *instr,\n-\t\t\t\tstruct instruction_data *data)\n-{\n-\tstruct action *a;\n+\t\tinstr->type = INSTR_REGWR_RIM;\n+\t\tif (src[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGWR_RIH;\n \n-\tCHECK(!action, EINVAL);\n-\tCHECK(n_tokens == 3, EINVAL);\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx_val = idx_val;\n+\t\tinstr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;\n+\t\tinstr->regarray.dstsrc.n_bits = fsrc->n_bits;\n+\t\tinstr->regarray.dstsrc.offset = fsrc->offset / 8;\n+\t\treturn 0;\n+\t}\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+\t/* REGWR_RII. */\n+\tsrc_val = strtoull(src, &src, 0);\n+\tCHECK(!src[0], EINVAL);\n \n-\ta = action_find(p, tokens[2]);\n-\tCHECK(a, EINVAL);\n+\tidx_val = strtoul(idx, &idx, 0);\n+\tCHECK(!idx[0], EINVAL);\n+\n+\tinstr->type = INSTR_REGWR_RII;\n+\tinstr->regarray.idx_val = idx_val;\n+\tinstr->regarray.dstsrc_val = src_val;\n \n-\tinstr->type = INSTR_JMP_ACTION_MISS;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n-\tinstr->jmp.action_id = a->id;\n \treturn 0;\n }\n \n static int\n-instr_jmp_eq_translate(struct rte_swx_pipeline *p,\n+instr_regadd_translate(struct rte_swx_pipeline *p,\n \t\t       struct action *action,\n \t\t       char **tokens,\n \t\t       int n_tokens,\n \t\t       struct instruction *instr,\n-\t\t       struct instruction_data *data)\n+\t\t       struct instruction_data *data __rte_unused)\n {\n-\tchar *a = tokens[2], *b = tokens[3];\n-\tstruct field *fa, *fb;\n-\tuint64_t b_val;\n-\tuint32_t a_struct_id, b_struct_id;\n+\tchar *regarray = tokens[1], *idx = tokens[2], *src = tokens[3];\n+\tstruct regarray *r;\n+\tstruct field *fidx, *fsrc;\n+\tuint64_t src_val;\n+\tuint32_t idx_struct_id, idx_val, src_struct_id;\n \n \tCHECK(n_tokens == 4, EINVAL);\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+\tr = regarray_find(p, regarray);\n+\tCHECK(r, EINVAL);\n \n-\tfa = struct_field_parse(p, action, a, &a_struct_id);\n-\tCHECK(fa, EINVAL);\n+\t/* REGADD_RHH, REGADD_RHM, REGADD_RMH, REGADD_RMM. */\n+\tfidx = struct_field_parse(p, action, idx, &idx_struct_id);\n+\tfsrc = struct_field_parse(p, action, src, &src_struct_id);\n+\tif (fidx && fsrc) {\n+\t\tinstr->type = INSTR_REGADD_RMM;\n+\t\tif (idx[0] == 'h' && src[0] != 'h')\n+\t\t\tinstr->type = INSTR_REGADD_RHM;\n+\t\tif (idx[0] != 'h' && src[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGADD_RMH;\n+\t\tif (idx[0] == 'h' && src[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGADD_RHH;\n+\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx.struct_id = (uint8_t)idx_struct_id;\n+\t\tinstr->regarray.idx.n_bits = fidx->n_bits;\n+\t\tinstr->regarray.idx.offset = fidx->offset / 8;\n+\t\tinstr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;\n+\t\tinstr->regarray.dstsrc.n_bits = fsrc->n_bits;\n+\t\tinstr->regarray.dstsrc.offset = fsrc->offset / 8;\n+\t\treturn 0;\n+\t}\n \n-\t/* JMP_EQ or JMP_EQ_S. */\n-\tfb = struct_field_parse(p, action, b, &b_struct_id);\n-\tif (fb) {\n-\t\tinstr->type = INSTR_JMP_EQ;\n-\t\tif ((a[0] == 'h' && b[0] != 'h') ||\n-\t\t    (a[0] != 'h' && b[0] == 'h'))\n-\t\t\tinstr->type = INSTR_JMP_EQ_S;\n-\t\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\t/* REGADD_RHI, REGADD_RMI. */\n+\tif (fidx && !fsrc) {\n+\t\tsrc_val = strtoull(src, &src, 0);\n+\t\tCHECK(!src[0], EINVAL);\n \n-\t\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n-\t\tinstr->jmp.a.n_bits = fa->n_bits;\n-\t\tinstr->jmp.a.offset = fa->offset / 8;\n-\t\tinstr->jmp.b.struct_id = (uint8_t)b_struct_id;\n-\t\tinstr->jmp.b.n_bits = fb->n_bits;\n-\t\tinstr->jmp.b.offset = fb->offset / 8;\n+\t\tinstr->type = INSTR_REGADD_RMI;\n+\t\tif (idx[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGADD_RHI;\n+\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx.struct_id = (uint8_t)idx_struct_id;\n+\t\tinstr->regarray.idx.n_bits = fidx->n_bits;\n+\t\tinstr->regarray.idx.offset = fidx->offset / 8;\n+\t\tinstr->regarray.dstsrc_val = src_val;\n \t\treturn 0;\n \t}\n \n-\t/* JMP_EQ_I. */\n-\tb_val = strtoull(b, &b, 0);\n-\tCHECK(!b[0], EINVAL);\n+\t/* REGADD_RIH, REGADD_RIM. */\n+\tif (!fidx && fsrc) {\n+\t\tidx_val = strtoul(idx, &idx, 0);\n+\t\tCHECK(!idx[0], EINVAL);\n \n-\tif (a[0] == 'h')\n-\t\tb_val = hton64(b_val) >> (64 - fa->n_bits);\n+\t\tinstr->type = INSTR_REGADD_RIM;\n+\t\tif (src[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGADD_RIH;\n \n-\tinstr->type = INSTR_JMP_EQ_I;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n-\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n-\tinstr->jmp.a.n_bits = fa->n_bits;\n-\tinstr->jmp.a.offset = fa->offset / 8;\n-\tinstr->jmp.b_val = b_val;\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx_val = idx_val;\n+\t\tinstr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;\n+\t\tinstr->regarray.dstsrc.n_bits = fsrc->n_bits;\n+\t\tinstr->regarray.dstsrc.offset = fsrc->offset / 8;\n+\t\treturn 0;\n+\t}\n+\n+\t/* REGADD_RII. */\n+\tsrc_val = strtoull(src, &src, 0);\n+\tCHECK(!src[0], EINVAL);\n+\n+\tidx_val = strtoul(idx, &idx, 0);\n+\tCHECK(!idx[0], EINVAL);\n+\n+\tinstr->type = INSTR_REGADD_RII;\n+\tinstr->regarray.idx_val = idx_val;\n+\tinstr->regarray.dstsrc_val = src_val;\n \treturn 0;\n }\n \n-static int\n-instr_jmp_neq_translate(struct rte_swx_pipeline *p,\n-\t\t\tstruct action *action,\n-\t\t\tchar **tokens,\n-\t\t\tint n_tokens,\n-\t\t\tstruct instruction *instr,\n-\t\t\tstruct instruction_data *data)\n+static inline uint64_t *\n+instr_regarray_regarray(struct rte_swx_pipeline *p, struct instruction *ip)\n {\n-\tchar *a = tokens[2], *b = tokens[3];\n-\tstruct field *fa, *fb;\n+\tstruct regarray_runtime *r = &p->regarray_runtime[ip->regarray.regarray_id];\n+\treturn r->regarray;\n+}\n+\n+static inline uint64_t\n+instr_regarray_idx_hbo(struct rte_swx_pipeline *p, struct thread *t, struct instruction *ip)\n+{\n+\tstruct regarray_runtime *r = &p->regarray_runtime[ip->regarray.regarray_id];\n+\n+\tuint8_t *idx_struct = t->structs[ip->regarray.idx.struct_id];\n+\tuint64_t *idx64_ptr = (uint64_t *)&idx_struct[ip->regarray.idx.offset];\n+\tuint64_t idx64 = *idx64_ptr;\n+\tuint64_t idx64_mask = UINT64_MAX >> (64 - ip->regarray.idx.n_bits);\n+\tuint64_t idx = idx64 & idx64_mask & r->size_mask;\n+\n+\treturn idx;\n+}\n+\n+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN\n+\n+static inline uint64_t\n+instr_regarray_idx_nbo(struct rte_swx_pipeline *p, struct thread *t, struct instruction *ip)\n+{\n+\tstruct regarray_runtime *r = &p->regarray_runtime[ip->regarray.regarray_id];\n+\n+\tuint8_t *idx_struct = t->structs[ip->regarray.idx.struct_id];\n+\tuint64_t *idx64_ptr = (uint64_t *)&idx_struct[ip->regarray.idx.offset];\n+\tuint64_t idx64 = *idx64_ptr;\n+\tuint64_t idx = (ntoh64(idx64) >> (64 - ip->regarray.idx.n_bits)) & r->size_mask;\n+\n+\treturn idx;\n+}\n+\n+#else\n+\n+#define instr_regarray_idx_nbo instr_regarray_idx_hbo\n+\n+#endif\n+\n+static inline uint64_t\n+instr_regarray_idx_imm(struct rte_swx_pipeline *p, struct instruction *ip)\n+{\n+\tstruct regarray_runtime *r = &p->regarray_runtime[ip->regarray.regarray_id];\n+\n+\tuint64_t idx = ip->regarray.idx_val & r->size_mask;\n+\n+\treturn idx;\n+}\n+\n+static inline uint64_t\n+instr_regarray_src_hbo(struct thread *t, struct instruction *ip)\n+{\n+\tuint8_t *src_struct = t->structs[ip->regarray.dstsrc.struct_id];\n+\tuint64_t *src64_ptr = (uint64_t *)&src_struct[ip->regarray.dstsrc.offset];\n+\tuint64_t src64 = *src64_ptr;\n+\tuint64_t src64_mask = UINT64_MAX >> (64 - ip->regarray.dstsrc.n_bits);\n+\tuint64_t src = src64 & src64_mask;\n+\n+\treturn src;\n+}\n+\n+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN\n+\n+static inline uint64_t\n+instr_regarray_src_nbo(struct thread *t, struct instruction *ip)\n+{\n+\tuint8_t *src_struct = t->structs[ip->regarray.dstsrc.struct_id];\n+\tuint64_t *src64_ptr = (uint64_t *)&src_struct[ip->regarray.dstsrc.offset];\n+\tuint64_t src64 = *src64_ptr;\n+\tuint64_t src = ntoh64(src64) >> (64 - ip->regarray.dstsrc.n_bits);\n+\n+\treturn src;\n+}\n+\n+#else\n+\n+#define instr_regarray_src_nbo instr_regarray_src_hbo\n+\n+#endif\n+\n+static inline void\n+instr_regarray_dst_hbo_src_hbo_set(struct thread *t, struct instruction *ip, uint64_t src)\n+{\n+\tuint8_t *dst_struct = t->structs[ip->regarray.dstsrc.struct_id];\n+\tuint64_t *dst64_ptr = (uint64_t *)&dst_struct[ip->regarray.dstsrc.offset];\n+\tuint64_t dst64 = *dst64_ptr;\n+\tuint64_t dst64_mask = UINT64_MAX >> (64 - ip->regarray.dstsrc.n_bits);\n+\n+\t*dst64_ptr = (dst64 & ~dst64_mask) | (src & dst64_mask);\n+\n+}\n+\n+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN\n+\n+static inline void\n+instr_regarray_dst_nbo_src_hbo_set(struct thread *t, struct instruction *ip, uint64_t src)\n+{\n+\tuint8_t *dst_struct = t->structs[ip->regarray.dstsrc.struct_id];\n+\tuint64_t *dst64_ptr = (uint64_t *)&dst_struct[ip->regarray.dstsrc.offset];\n+\tuint64_t dst64 = *dst64_ptr;\n+\tuint64_t dst64_mask = UINT64_MAX >> (64 - ip->regarray.dstsrc.n_bits);\n+\n+\tsrc = hton64(src) >> (64 - ip->regarray.dstsrc.n_bits);\n+\t*dst64_ptr = (dst64 & ~dst64_mask) | (src & dst64_mask);\n+}\n+\n+#else\n+\n+#define instr_regarray_dst_nbo_src_hbo_set instr_regarray_dst_hbo_src_hbo_set\n+\n+#endif\n+\n+static inline void\n+instr_regprefetch_rh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx;\n+\n+\tTRACE(\"[Thread %2u] regprefetch (r[h])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_nbo(p, t, ip);\n+\trte_prefetch0(&regarray[idx]);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regprefetch_rm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx;\n+\n+\tTRACE(\"[Thread %2u] regprefetch (r[m])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_hbo(p, t, ip);\n+\trte_prefetch0(&regarray[idx]);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regprefetch_ri_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx;\n+\n+\tTRACE(\"[Thread %2u] regprefetch (r[i])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_imm(p, ip);\n+\trte_prefetch0(&regarray[idx]);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regrd_hrh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx;\n+\n+\tTRACE(\"[Thread %2u] regrd (h = r[h])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_nbo(p, t, ip);\n+\tinstr_regarray_dst_nbo_src_hbo_set(t, ip, regarray[idx]);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regrd_hrm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx;\n+\n+\tTRACE(\"[Thread %2u] regrd (h = r[m])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_hbo(p, t, ip);\n+\tinstr_regarray_dst_nbo_src_hbo_set(t, ip, regarray[idx]);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regrd_mrh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx;\n+\n+\tTRACE(\"[Thread %2u] regrd (m = r[h])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_nbo(p, t, ip);\n+\tinstr_regarray_dst_hbo_src_hbo_set(t, ip, regarray[idx]);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regrd_mrm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx;\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_hbo(p, t, ip);\n+\tinstr_regarray_dst_hbo_src_hbo_set(t, ip, regarray[idx]);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regrd_hri_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx;\n+\n+\tTRACE(\"[Thread %2u] regrd (h = r[i])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_imm(p, ip);\n+\tinstr_regarray_dst_nbo_src_hbo_set(t, ip, regarray[idx]);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regrd_mri_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx;\n+\n+\tTRACE(\"[Thread %2u] regrd (m = r[i])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_imm(p, ip);\n+\tinstr_regarray_dst_hbo_src_hbo_set(t, ip, regarray[idx]);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rhh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[h] = h)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_nbo(p, t, ip);\n+\tsrc = instr_regarray_src_nbo(t, ip);\n+\tregarray[idx] = src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rhm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[h] = m)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_nbo(p, t, ip);\n+\tsrc = instr_regarray_src_hbo(t, ip);\n+\tregarray[idx] = src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rmh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[m] = h)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_hbo(p, t, ip);\n+\tsrc = instr_regarray_src_nbo(t, ip);\n+\tregarray[idx] = src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rmm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[m] = m)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_hbo(p, t, ip);\n+\tsrc = instr_regarray_src_hbo(t, ip);\n+\tregarray[idx] = src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rhi_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[h] = i)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_nbo(p, t, ip);\n+\tsrc = ip->regarray.dstsrc_val;\n+\tregarray[idx] = src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rmi_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[m] = i)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_hbo(p, t, ip);\n+\tsrc = ip->regarray.dstsrc_val;\n+\tregarray[idx] = src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rih_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[i] = h)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_imm(p, ip);\n+\tsrc = instr_regarray_src_nbo(t, ip);\n+\tregarray[idx] = src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rim_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[i] = m)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_imm(p, ip);\n+\tsrc = instr_regarray_src_hbo(t, ip);\n+\tregarray[idx] = src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rii_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[i] = i)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_imm(p, ip);\n+\tsrc = ip->regarray.dstsrc_val;\n+\tregarray[idx] = src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rhh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[h] += h)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_nbo(p, t, ip);\n+\tsrc = instr_regarray_src_nbo(t, ip);\n+\tregarray[idx] += src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rhm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[h] += m)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_nbo(p, t, ip);\n+\tsrc = instr_regarray_src_hbo(t, ip);\n+\tregarray[idx] += src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rmh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[m] += h)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_hbo(p, t, ip);\n+\tsrc = instr_regarray_src_nbo(t, ip);\n+\tregarray[idx] += src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rmm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[m] += m)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_hbo(p, t, ip);\n+\tsrc = instr_regarray_src_hbo(t, ip);\n+\tregarray[idx] += src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rhi_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[h] += i)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_nbo(p, t, ip);\n+\tsrc = ip->regarray.dstsrc_val;\n+\tregarray[idx] += src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rmi_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[m] += i)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_hbo(p, t, ip);\n+\tsrc = ip->regarray.dstsrc_val;\n+\tregarray[idx] += src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rih_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[i] += h)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_imm(p, ip);\n+\tsrc = instr_regarray_src_nbo(t, ip);\n+\tregarray[idx] += src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rim_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[i] += m)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_imm(p, ip);\n+\tsrc = instr_regarray_src_hbo(t, ip);\n+\tregarray[idx] += src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rii_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint64_t *regarray, idx, src;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[i] += i)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tregarray = instr_regarray_regarray(p, ip);\n+\tidx = instr_regarray_idx_imm(p, ip);\n+\tsrc = ip->regarray.dstsrc_val;\n+\tregarray[idx] += src;\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+/*\n+ * jmp.\n+ */\n+static struct action *\n+action_find(struct rte_swx_pipeline *p, const char *name);\n+\n+static int\n+instr_jmp_translate(struct rte_swx_pipeline *p __rte_unused,\n+\t\t    struct action *action __rte_unused,\n+\t\t    char **tokens,\n+\t\t    int n_tokens,\n+\t\t    struct instruction *instr,\n+\t\t    struct instruction_data *data)\n+{\n+\tCHECK(n_tokens == 2, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\tinstr->type = INSTR_JMP;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_valid_translate(struct rte_swx_pipeline *p,\n+\t\t\t  struct action *action __rte_unused,\n+\t\t\t  char **tokens,\n+\t\t\t  int n_tokens,\n+\t\t\t  struct instruction *instr,\n+\t\t\t  struct instruction_data *data)\n+{\n+\tstruct header *h;\n+\n+\tCHECK(n_tokens == 3, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\th = header_parse(p, tokens[2]);\n+\tCHECK(h, EINVAL);\n+\n+\tinstr->type = INSTR_JMP_VALID;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.header_id = h->id;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_invalid_translate(struct rte_swx_pipeline *p,\n+\t\t\t    struct action *action __rte_unused,\n+\t\t\t    char **tokens,\n+\t\t\t    int n_tokens,\n+\t\t\t    struct instruction *instr,\n+\t\t\t    struct instruction_data *data)\n+{\n+\tstruct header *h;\n+\n+\tCHECK(n_tokens == 3, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\th = header_parse(p, tokens[2]);\n+\tCHECK(h, EINVAL);\n+\n+\tinstr->type = INSTR_JMP_INVALID;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.header_id = h->id;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_hit_translate(struct rte_swx_pipeline *p __rte_unused,\n+\t\t\tstruct action *action,\n+\t\t\tchar **tokens,\n+\t\t\tint n_tokens,\n+\t\t\tstruct instruction *instr,\n+\t\t\tstruct instruction_data *data)\n+{\n+\tCHECK(!action, EINVAL);\n+\tCHECK(n_tokens == 2, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\tinstr->type = INSTR_JMP_HIT;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_miss_translate(struct rte_swx_pipeline *p __rte_unused,\n+\t\t\t struct action *action,\n+\t\t\t char **tokens,\n+\t\t\t int n_tokens,\n+\t\t\t struct instruction *instr,\n+\t\t\t struct instruction_data *data)\n+{\n+\tCHECK(!action, EINVAL);\n+\tCHECK(n_tokens == 2, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\tinstr->type = INSTR_JMP_MISS;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_action_hit_translate(struct rte_swx_pipeline *p,\n+\t\t\t       struct action *action,\n+\t\t\t       char **tokens,\n+\t\t\t       int n_tokens,\n+\t\t\t       struct instruction *instr,\n+\t\t\t       struct instruction_data *data)\n+{\n+\tstruct action *a;\n+\n+\tCHECK(!action, EINVAL);\n+\tCHECK(n_tokens == 3, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\ta = action_find(p, tokens[2]);\n+\tCHECK(a, EINVAL);\n+\n+\tinstr->type = INSTR_JMP_ACTION_HIT;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.action_id = a->id;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_action_miss_translate(struct rte_swx_pipeline *p,\n+\t\t\t\tstruct action *action,\n+\t\t\t\tchar **tokens,\n+\t\t\t\tint n_tokens,\n+\t\t\t\tstruct instruction *instr,\n+\t\t\t\tstruct instruction_data *data)\n+{\n+\tstruct action *a;\n+\n+\tCHECK(!action, EINVAL);\n+\tCHECK(n_tokens == 3, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\ta = action_find(p, tokens[2]);\n+\tCHECK(a, EINVAL);\n+\n+\tinstr->type = INSTR_JMP_ACTION_MISS;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.action_id = a->id;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_eq_translate(struct rte_swx_pipeline *p,\n+\t\t       struct action *action,\n+\t\t       char **tokens,\n+\t\t       int n_tokens,\n+\t\t       struct instruction *instr,\n+\t\t       struct instruction_data *data)\n+{\n+\tchar *a = tokens[2], *b = tokens[3];\n+\tstruct field *fa, *fb;\n+\tuint64_t b_val;\n+\tuint32_t a_struct_id, b_struct_id;\n+\n+\tCHECK(n_tokens == 4, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\tfa = struct_field_parse(p, action, a, &a_struct_id);\n+\tCHECK(fa, EINVAL);\n+\n+\t/* JMP_EQ or JMP_EQ_S. */\n+\tfb = struct_field_parse(p, action, b, &b_struct_id);\n+\tif (fb) {\n+\t\tinstr->type = INSTR_JMP_EQ;\n+\t\tif ((a[0] == 'h' && b[0] != 'h') ||\n+\t\t    (a[0] != 'h' && b[0] == 'h'))\n+\t\t\tinstr->type = INSTR_JMP_EQ_S;\n+\t\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\n+\t\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n+\t\tinstr->jmp.a.n_bits = fa->n_bits;\n+\t\tinstr->jmp.a.offset = fa->offset / 8;\n+\t\tinstr->jmp.b.struct_id = (uint8_t)b_struct_id;\n+\t\tinstr->jmp.b.n_bits = fb->n_bits;\n+\t\tinstr->jmp.b.offset = fb->offset / 8;\n+\t\treturn 0;\n+\t}\n+\n+\t/* JMP_EQ_I. */\n+\tb_val = strtoull(b, &b, 0);\n+\tCHECK(!b[0], EINVAL);\n+\n+\tif (a[0] == 'h')\n+\t\tb_val = hton64(b_val) >> (64 - fa->n_bits);\n+\n+\tinstr->type = INSTR_JMP_EQ_I;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n+\tinstr->jmp.a.n_bits = fa->n_bits;\n+\tinstr->jmp.a.offset = fa->offset / 8;\n+\tinstr->jmp.b_val = b_val;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_neq_translate(struct rte_swx_pipeline *p,\n+\t\t\tstruct action *action,\n+\t\t\tchar **tokens,\n+\t\t\tint n_tokens,\n+\t\t\tstruct instruction *instr,\n+\t\t\tstruct instruction_data *data)\n+{\n+\tchar *a = tokens[2], *b = tokens[3];\n+\tstruct field *fa, *fb;\n \tuint64_t b_val;\n \tuint32_t a_struct_id, b_struct_id;\n \n@@ -5475,6 +6511,38 @@ instr_translate(struct rte_swx_pipeline *p,\n \t\t\t\t\t       instr,\n \t\t\t\t\t       data);\n \n+\tif (!strcmp(tokens[tpos], \"regprefetch\"))\n+\t\treturn instr_regprefetch_translate(p,\n+\t\t\t\t\t\t   action,\n+\t\t\t\t\t\t   &tokens[tpos],\n+\t\t\t\t\t\t   n_tokens - tpos,\n+\t\t\t\t\t\t   instr,\n+\t\t\t\t\t\t   data);\n+\n+\tif (!strcmp(tokens[tpos], \"regrd\"))\n+\t\treturn instr_regrd_translate(p,\n+\t\t\t\t\t     action,\n+\t\t\t\t\t     &tokens[tpos],\n+\t\t\t\t\t     n_tokens - tpos,\n+\t\t\t\t\t     instr,\n+\t\t\t\t\t     data);\n+\n+\tif (!strcmp(tokens[tpos], \"regwr\"))\n+\t\treturn instr_regwr_translate(p,\n+\t\t\t\t\t     action,\n+\t\t\t\t\t     &tokens[tpos],\n+\t\t\t\t\t     n_tokens - tpos,\n+\t\t\t\t\t     instr,\n+\t\t\t\t\t     data);\n+\n+\tif (!strcmp(tokens[tpos], \"regadd\"))\n+\t\treturn instr_regadd_translate(p,\n+\t\t\t\t\t      action,\n+\t\t\t\t\t      &tokens[tpos],\n+\t\t\t\t\t      n_tokens - tpos,\n+\t\t\t\t\t      instr,\n+\t\t\t\t\t      data);\n+\n \tif (!strcmp(tokens[tpos], \"table\"))\n \t\treturn instr_table_translate(p,\n \t\t\t\t\t     action,\n@@ -6111,6 +7179,37 @@ static instr_exec_t instruction_table[] = {\n \t[INSTR_ALU_SHR_MI] = instr_alu_shr_mi_exec,\n \t[INSTR_ALU_SHR_HI] = instr_alu_shr_hi_exec,\n \n+\t[INSTR_REGPREFETCH_RH] = instr_regprefetch_rh_exec,\n+\t[INSTR_REGPREFETCH_RM] = instr_regprefetch_rm_exec,\n+\t[INSTR_REGPREFETCH_RI] = instr_regprefetch_ri_exec,\n+\n+\t[INSTR_REGRD_HRH] = instr_regrd_hrh_exec,\n+\t[INSTR_REGRD_HRM] = instr_regrd_hrm_exec,\n+\t[INSTR_REGRD_MRH] = instr_regrd_mrh_exec,\n+\t[INSTR_REGRD_MRM] = instr_regrd_mrm_exec,\n+\t[INSTR_REGRD_HRI] = instr_regrd_hri_exec,\n+\t[INSTR_REGRD_MRI] = instr_regrd_mri_exec,\n+\n+\t[INSTR_REGWR_RHH] = instr_regwr_rhh_exec,\n+\t[INSTR_REGWR_RHM] = instr_regwr_rhm_exec,\n+\t[INSTR_REGWR_RMH] = instr_regwr_rmh_exec,\n+\t[INSTR_REGWR_RMM] = instr_regwr_rmm_exec,\n+\t[INSTR_REGWR_RHI] = instr_regwr_rhi_exec,\n+\t[INSTR_REGWR_RMI] = instr_regwr_rmi_exec,\n+\t[INSTR_REGWR_RIH] = instr_regwr_rih_exec,\n+\t[INSTR_REGWR_RIM] = instr_regwr_rim_exec,\n+\t[INSTR_REGWR_RII] = instr_regwr_rii_exec,\n+\n+\t[INSTR_REGADD_RHH] = instr_regadd_rhh_exec,\n+\t[INSTR_REGADD_RHM] = instr_regadd_rhm_exec,\n+\t[INSTR_REGADD_RMH] = instr_regadd_rmh_exec,\n+\t[INSTR_REGADD_RMM] = instr_regadd_rmm_exec,\n+\t[INSTR_REGADD_RHI] = instr_regadd_rhi_exec,\n+\t[INSTR_REGADD_RMI] = instr_regadd_rmi_exec,\n+\t[INSTR_REGADD_RIH] = instr_regadd_rih_exec,\n+\t[INSTR_REGADD_RIM] = instr_regadd_rim_exec,\n+\t[INSTR_REGADD_RII] = instr_regadd_rii_exec,\n+\n \t[INSTR_TABLE] = instr_table_exec,\n \t[INSTR_EXTERN_OBJ] = instr_extern_obj_exec,\n \t[INSTR_EXTERN_FUNC] = instr_extern_func_exec,\n@@ -6823,6 +7922,132 @@ table_free(struct rte_swx_pipeline *p)\n \t}\n }\n \n+/*\n+ * Register array.\n+ */\n+static struct regarray *\n+regarray_find(struct rte_swx_pipeline *p, const char *name)\n+{\n+\tstruct regarray *elem;\n+\n+\tTAILQ_FOREACH(elem, &p->regarrays, node)\n+\t\tif (!strcmp(elem->name, name))\n+\t\t\treturn elem;\n+\n+\treturn NULL;\n+}\n+\n+static struct regarray *\n+regarray_find_by_id(struct rte_swx_pipeline *p, uint32_t id)\n+{\n+\tstruct regarray *elem = NULL;\n+\n+\tTAILQ_FOREACH(elem, &p->regarrays, node)\n+\t\tif (elem->id == id)\n+\t\t\treturn elem;\n+\n+\treturn NULL;\n+}\n+\n+int\n+rte_swx_pipeline_regarray_config(struct rte_swx_pipeline *p,\n+\t\t\t      const char *name,\n+\t\t\t      uint32_t size,\n+\t\t\t      uint64_t init_val)\n+{\n+\tstruct regarray *r;\n+\n+\tCHECK(p, EINVAL);\n+\n+\tCHECK_NAME(name, EINVAL);\n+\tCHECK(!regarray_find(p, name), EEXIST);\n+\n+\tCHECK(size, EINVAL);\n+\tsize = rte_align32pow2(size);\n+\n+\t/* Memory allocation. */\n+\tr = calloc(1, sizeof(struct regarray));\n+\tCHECK(r, ENOMEM);\n+\n+\t/* Node initialization. */\n+\tstrcpy(r->name, name);\n+\tr->init_val = init_val;\n+\tr->size = size;\n+\tr->id = p->n_regarrays;\n+\n+\t/* Node add to tailq. */\n+\tTAILQ_INSERT_TAIL(&p->regarrays, r, node);\n+\tp->n_regarrays++;\n+\n+\treturn 0;\n+}\n+\n+static int\n+regarray_build(struct rte_swx_pipeline *p)\n+{\n+\tstruct regarray *regarray;\n+\n+\tif (!p->n_regarrays)\n+\t\treturn 0;\n+\n+\tp->regarray_runtime = calloc(p->n_regarrays, sizeof(struct regarray_runtime));\n+\tCHECK(p->regarray_runtime, ENOMEM);\n+\n+\tTAILQ_FOREACH(regarray, &p->regarrays, node) {\n+\t\tstruct regarray_runtime *r = &p->regarray_runtime[regarray->id];\n+\t\tuint32_t i;\n+\n+\t\tr->regarray = env_malloc(regarray->size * sizeof(uint64_t),\n+\t\t\t\t\t RTE_CACHE_LINE_SIZE,\n+\t\t\t\t\t p->numa_node);\n+\t\tCHECK(r->regarray, ENOMEM);\n+\n+\t\tif (regarray->init_val)\n+\t\t\tfor (i = 0; i < regarray->size; i++)\n+\t\t\t\tr->regarray[i] = regarray->init_val;\n+\n+\t\tr->size_mask = regarray->size - 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void\n+regarray_build_free(struct rte_swx_pipeline *p)\n+{\n+\tuint32_t i;\n+\n+\tif (!p->regarray_runtime)\n+\t\treturn;\n+\n+\tfor (i = 0; i < p->n_regarrays; i++) {\n+\t\tstruct regarray *regarray = regarray_find_by_id(p, i);\n+\t\tstruct regarray_runtime *r = &p->regarray_runtime[i];\n+\n+\t\tenv_free(r->regarray, regarray->size * sizeof(uint64_t));\n+\t}\n+\n+\tfree(p->regarray_runtime);\n+\tp->regarray_runtime = NULL;\n+}\n+\n+static void\n+regarray_free(struct rte_swx_pipeline *p)\n+{\n+\tregarray_build_free(p);\n+\n+\tfor ( ; ; ) {\n+\t\tstruct regarray *elem;\n+\n+\t\telem = TAILQ_FIRST(&p->regarrays);\n+\t\tif (!elem)\n+\t\t\tbreak;\n+\n+\t\tTAILQ_REMOVE(&p->regarrays, elem, node);\n+\t\tfree(elem);\n+\t}\n+}\n+\n /*\n  * Pipeline.\n  */\n@@ -6851,6 +8076,7 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)\n \tTAILQ_INIT(&pipeline->actions);\n \tTAILQ_INIT(&pipeline->table_types);\n \tTAILQ_INIT(&pipeline->tables);\n+\tTAILQ_INIT(&pipeline->regarrays);\n \n \tpipeline->n_structs = 1; /* Struct 0 is reserved for action_data. */\n \tpipeline->numa_node = numa_node;\n@@ -6867,6 +8093,7 @@ rte_swx_pipeline_free(struct rte_swx_pipeline *p)\n \n \tfree(p->instructions);\n \n+\tregarray_free(p);\n \ttable_state_free(p);\n \ttable_free(p);\n \taction_free(p);\n@@ -6951,10 +8178,15 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p)\n \tif (status)\n \t\tgoto error;\n \n+\tstatus = regarray_build(p);\n+\tif (status)\n+\t\tgoto error;\n+\n \tp->build_done = 1;\n \treturn 0;\n \n error:\n+\tregarray_build_free(p);\n \ttable_state_build_free(p);\n \ttable_build_free(p);\n \taction_build_free(p);\n@@ -7015,6 +8247,7 @@ rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p,\n \tpipeline->n_ports_out = p->n_ports_out;\n \tpipeline->n_actions = n_actions;\n \tpipeline->n_tables = n_tables;\n+\tpipeline->n_regarrays = p->n_regarrays;\n \n \treturn 0;\n }\n@@ -7222,3 +8455,64 @@ rte_swx_ctl_pipeline_port_out_stats_read(struct rte_swx_pipeline *p,\n \tport->type->ops.stats_read(port->obj, stats);\n \treturn 0;\n }\n+\n+int\n+rte_swx_ctl_regarray_info_get(struct rte_swx_pipeline *p,\n+\t\t\t      uint32_t regarray_id,\n+\t\t\t      struct rte_swx_ctl_regarray_info *regarray)\n+{\n+\tstruct regarray *r;\n+\n+\tif (!p || !regarray)\n+\t\treturn -EINVAL;\n+\n+\tr = regarray_find_by_id(p, regarray_id);\n+\tif (!r)\n+\t\treturn -EINVAL;\n+\n+\tstrcpy(regarray->name, r->name);\n+\tregarray->size = r->size;\n+\treturn 0;\n+}\n+\n+int\n+rte_swx_ctl_pipeline_regarray_read(struct rte_swx_pipeline *p,\n+\t\t\t\t   const char *regarray_name,\n+\t\t\t\t   uint32_t regarray_index,\n+\t\t\t\t   uint64_t *value)\n+{\n+\tstruct regarray *regarray;\n+\tstruct regarray_runtime *r;\n+\n+\tif (!p || !regarray_name || !value)\n+\t\treturn -EINVAL;\n+\n+\tregarray = regarray_find(p, regarray_name);\n+\tif (!regarray || (regarray_index >= regarray->size))\n+\t\treturn -EINVAL;\n+\n+\tr = &p->regarray_runtime[regarray->id];\n+\t*value = r->regarray[regarray_index];\n+\treturn 0;\n+}\n+\n+int\n+rte_swx_ctl_pipeline_regarray_write(struct rte_swx_pipeline *p,\n+\t\t\t\t   const char *regarray_name,\n+\t\t\t\t   uint32_t regarray_index,\n+\t\t\t\t   uint64_t value)\n+{\n+\tstruct regarray *regarray;\n+\tstruct regarray_runtime *r;\n+\n+\tif (!p || !regarray_name)\n+\t\treturn -EINVAL;\n+\n+\tregarray = regarray_find(p, regarray_name);\n+\tif (!regarray || (regarray_index >= regarray->size))\n+\t\treturn -EINVAL;\n+\n+\tr = &p->regarray_runtime[regarray->id];\n+\tr->regarray[regarray_index] = value;\n+\treturn 0;\n+}\ndiff --git a/lib/librte_pipeline/rte_swx_pipeline.h b/lib/librte_pipeline/rte_swx_pipeline.h\nindex f0a2cef77..1c9b2eb12 100644\n--- a/lib/librte_pipeline/rte_swx_pipeline.h\n+++ b/lib/librte_pipeline/rte_swx_pipeline.h\n@@ -616,6 +616,30 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p,\n \t\t\t      const char *args,\n \t\t\t      uint32_t size);\n \n+/**\n+ * Pipeline register array configure\n+ *\n+ * @param[in] p\n+ *   Pipeline handle.\n+ * @param[in] name\n+ *   Register array name.\n+ * @param[in] size\n+ *   Number of registers in the array. Each register is 64-bit in size.\n+ * @param[in] init_val\n+ *   Initial value for every register in the array. The recommended value is 0.\n+ * @return\n+ *   0 on success or the following error codes otherwise:\n+ *   -EINVAL: Invalid argument;\n+ *   -ENOMEM: Not enough space/cannot allocate memory;\n+ *   -EEXIST: Register array with this name already exists.\n+ */\n+__rte_experimental\n+int\n+rte_swx_pipeline_regarray_config(struct rte_swx_pipeline *p,\n+\t\t\t\t const char *name,\n+\t\t\t\t uint32_t size,\n+\t\t\t\t uint64_t init_val);\n+\n /**\n  * Pipeline instructions configure\n  *\ndiff --git a/lib/librte_pipeline/rte_swx_pipeline_spec.c b/lib/librte_pipeline/rte_swx_pipeline_spec.c\nindex f7884491b..0d0bca2ed 100644\n--- a/lib/librte_pipeline/rte_swx_pipeline_spec.c\n+++ b/lib/librte_pipeline/rte_swx_pipeline_spec.c\n@@ -940,6 +940,81 @@ table_block_parse(struct table_spec *s,\n \treturn -EINVAL;\n }\n \n+/*\n+ * regarray.\n+ *\n+ * regarray NAME size SIZE initval INITVAL\n+ */\n+struct regarray_spec {\n+\tchar *name;\n+\tuint64_t init_val;\n+\tuint32_t size;\n+};\n+\n+static void\n+regarray_spec_free(struct regarray_spec *s)\n+{\n+\tif (!s)\n+\t\treturn;\n+\n+\tfree(s->name);\n+\ts->name = NULL;\n+}\n+\n+static int\n+regarray_statement_parse(struct regarray_spec *s,\n+\t\t\t char **tokens,\n+\t\t\t uint32_t n_tokens,\n+\t\t\t uint32_t n_lines,\n+\t\t\t uint32_t *err_line,\n+\t\t\t const char **err_msg)\n+{\n+\tchar *p;\n+\n+\t/* Check format. */\n+\tif ((n_tokens != 6) ||\n+\t     strcmp(tokens[2], \"size\") ||\n+\t     strcmp(tokens[4], \"initval\")) {\n+\t\tif (err_line)\n+\t\t\t*err_line = n_lines;\n+\t\tif (err_msg)\n+\t\t\t*err_msg = \"Invalid regarray statement.\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* spec. */\n+\ts->name = strdup(tokens[1]);\n+\tif (!s->name) {\n+\t\tif (err_line)\n+\t\t\t*err_line = n_lines;\n+\t\tif (err_msg)\n+\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tp = tokens[3];\n+\ts->size = strtoul(p, &p, 0);\n+\tif (p[0] || !s->size) {\n+\t\tif (err_line)\n+\t\t\t*err_line = n_lines;\n+\t\tif (err_msg)\n+\t\t\t*err_msg = \"Invalid size argument.\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tp = tokens[5];\n+\ts->init_val = strtoull(p, &p, 0);\n+\tif (p[0]) {\n+\t\tif (err_line)\n+\t\t\t*err_line = n_lines;\n+\t\tif (err_msg)\n+\t\t\t*err_msg = \"Invalid initval argument.\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n /*\n  * apply.\n  *\n@@ -1066,6 +1141,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \tstruct metadata_spec metadata_spec = {0};\n \tstruct action_spec action_spec = {0};\n \tstruct table_spec table_spec = {0};\n+\tstruct regarray_spec regarray_spec = {0};\n \tstruct apply_spec apply_spec = {0};\n \tuint32_t n_lines;\n \tuint32_t block_mask = 0;\n@@ -1405,6 +1481,34 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \t\t\tcontinue;\n \t\t}\n \n+\t\t/* regarray. */\n+\t\tif (!strcmp(tokens[0], \"regarray\")) {\n+\t\t\tstatus = regarray_statement_parse(&regarray_spec,\n+\t\t\t\t\t\t\t  tokens,\n+\t\t\t\t\t\t\t  n_tokens,\n+\t\t\t\t\t\t\t  n_lines,\n+\t\t\t\t\t\t\t  err_line,\n+\t\t\t\t\t\t\t  err_msg);\n+\t\t\tif (status)\n+\t\t\t\tgoto error;\n+\n+\t\t\tstatus = rte_swx_pipeline_regarray_config(p,\n+\t\t\t\tregarray_spec.name,\n+\t\t\t\tregarray_spec.size,\n+\t\t\t\tregarray_spec.init_val);\n+\t\t\tif (status) {\n+\t\t\t\tif (err_line)\n+\t\t\t\t\t*err_line = n_lines;\n+\t\t\t\tif (err_msg)\n+\t\t\t\t\t*err_msg = \"Register array configuration error.\";\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\n+\t\t\tregarray_spec_free(&regarray_spec);\n+\n+\t\t\tcontinue;\n+\t\t}\n+\n \t\t/* apply. */\n \t\tif (!strcmp(tokens[0], \"apply\")) {\n \t\t\tstatus = apply_statement_parse(&block_mask,\n@@ -1457,6 +1561,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \tmetadata_spec_free(&metadata_spec);\n \taction_spec_free(&action_spec);\n \ttable_spec_free(&table_spec);\n+\tregarray_spec_free(&regarray_spec);\n \tapply_spec_free(&apply_spec);\n \treturn status;\n }\ndiff --git a/lib/librte_pipeline/version.map b/lib/librte_pipeline/version.map\nindex 87c826f1b..26a9edf47 100644\n--- a/lib/librte_pipeline/version.map\n+++ b/lib/librte_pipeline/version.map\n@@ -102,4 +102,10 @@ EXPERIMENTAL {\n \trte_swx_pipeline_table_state_get;\n \trte_swx_pipeline_table_state_set;\n \trte_swx_pipeline_table_type_register;\n+\n+\t#added in 21.05\n+\trte_swx_ctl_pipeline_regarray_read;\n+\trte_swx_ctl_pipeline_regarray_write;\n+\trte_swx_ctl_regarray_info_get;\n+\trte_swx_pipeline_regarray_config;\n };\n",
    "prefixes": [
        "v4",
        "1/2"
    ]
}