diff --git a/.github/workflows/issue_comment.yml b/.github/workflows/issue_comment.yml new file mode 100644 index 000000000000..a339e2310b6f --- /dev/null +++ b/.github/workflows/issue_comment.yml @@ -0,0 +1,20 @@ +name: Sync issue comments to JIRA + +# This workflow will be triggered when new issue comment is created (including PR comments) +on: issue_comment + +jobs: + sync_issue_comments_to_jira: + name: Sync Issue Comments to Jira + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync issue comments to JIRA + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: QEMU + JIRA_COMPONENT: GitHub + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.github/workflows/lockdown.yml b/.github/workflows/lockdown.yml deleted file mode 100644 index d5e1265cffb3..000000000000 --- a/.github/workflows/lockdown.yml +++ /dev/null @@ -1,30 +0,0 @@ -# Configuration for Repo Lockdown - https://github.com/dessant/repo-lockdown - -name: 'Repo Lockdown' - -on: - pull_request_target: - types: opened - -permissions: - pull-requests: write - -jobs: - action: - runs-on: ubuntu-latest - steps: - - uses: dessant/repo-lockdown@v2 - with: - pr-comment: | - Thank you for your interest in the QEMU project. - - This repository is a read-only mirror of the project's repostories hosted - on https://gitlab.com/qemu-project/qemu.git. - The project does not process merge requests filed on GitHub. - - QEMU welcomes contributions of code (either fixing bugs or adding new - functionality). However, we get a lot of patches, and so we have some - guidelines about contributing on the project website: - https://www.qemu.org/contribute/ - lock-pr: true - close-pr: true diff --git a/.github/workflows/new_issues.yml b/.github/workflows/new_issues.yml new file mode 100644 index 000000000000..002e8cb680de --- /dev/null +++ b/.github/workflows/new_issues.yml @@ -0,0 +1,20 @@ +name: Sync issues to Jira + +# This workflow will be triggered when a new issue is opened +on: issues + +jobs: + sync_issues_to_jira: + name: Sync issues to Jira + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync GitHub issues to Jira project + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: QEMU + JIRA_COMPONENT: GitHub + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.github/workflows/new_prs.yml b/.github/workflows/new_prs.yml new file mode 100644 index 000000000000..3dcfce840c1c --- /dev/null +++ b/.github/workflows/new_prs.yml @@ -0,0 +1,25 @@ +name: Sync remain PRs to Jira + +# This workflow will be triggered every hour, to sync remaining PRs (i.e. PRs with zero comment) to Jira project +# Note that, PRs can also get synced when new PR comment is created +on: + schedule: + - cron: "0 * * * *" + +jobs: + sync_prs_to_jira: + name: Sync PRs to Jira + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync PRs to Jira project + uses: espressif/github-actions/sync_issues_to_jira@master + with: + cron_job: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: QEMU + JIRA_COMPONENT: GitHub + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9762dda2ee3a..73ef191f1760 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,24 +1,57 @@ -# -# This is the GitLab CI configuration file for the mainstream QEMU -# project: https://gitlab.com/qemu-project/qemu/-/pipelines -# -# !!! DO NOT ADD ANY NEW CONFIGURATION TO THIS FILE !!! -# -# Only documentation or comments is accepted. -# -# To use a different set of jobs than the mainstream QEMU project, -# you need to set the location of your custom yml file at "custom CI/CD -# configuration path", on your GitLab CI namespace: -# https://docs.gitlab.com/ee/ci/pipelines/settings.html#custom-cicd-configuration-path -# -# ---------------------------------------------------------------------- -# -# QEMU CI jobs are based on templates. Some templates provide -# user-configurable options, modifiable via configuration variables. -# -# See https://qemu-project.gitlab.io/qemu/devel/ci.html#custom-ci-cd-variables -# for more information. -# +stages: + - build + - deploy -include: - - local: '/.gitlab-ci.d/qemu-project.yml' +build-linux: + stage: build + image: $CI_DOCKER_REGISTRY/qemu-build:5 + tags: + - build + - amd64 + artifacts: + paths: + - dist/esp-qemu-*.tar.bz2 + - dist/archive_name_* + expire_in: 1 week + parallel: + matrix: + - PLATFORM: [x86_64-linux-gnu] + TARGET: [riscv32-linux-user, xtensa-softmmu, riscv32-softmmu] + script: + - ./configure --prefix=/opt/qemu --target-list=${TARGET} --extra-cflags=-Werror --disable-capstone --disable-vnc --disable-sdl --disable-gtk --enable-gcrypt --enable-slirp + - ninja -C build install + - find /opt/qemu/share/qemu -maxdepth 1 -mindepth 1 -not -name 'esp*.bin' -exec rm -rf {} \; + - mkdir -p dist + - DIST_DIR=${PWD}/dist + + - VERSION=${CI_COMMIT_TAG:-""} + - VERSION=${VERSION#"esp-v"} # remove prefix in tags like `esp-v7.1.0_20221221` + - VERSION=${VERSION#"esp-"} # remove prefix in tags like `esp-develop-20221221` + - VERSION=${VERSION//"-"/"_"} # replace dashes with underscores in the version + - VERSION=${VERSION:-${CI_COMMIT_SHORT_SHA}} + + - export ARCHIVE_NAME=esp-qemu-${TARGET}-${VERSION}-${PLATFORM}.tar.bz2 + - cd /opt + - tar cjvf ${DIST_DIR}/${ARCHIVE_NAME} qemu + - echo $ARCHIVE_NAME >${DIST_DIR}/archive_name_${TARGET}_${PLATFORM} + +upload_to_http: + image: espressif/scp + stage: deploy + tags: + - deploy + - shiny + when: manual + allow_failure: true + variables: + # don't use "GIT_STRATEGY: none", because we need cleaning old artifacts in 'dist/' that came from previous pipelines + SSH_KEY: "$HTTP_UPLOAD_KEY" # used inside 'espressif/scp' + script: + # List of archives in dist/ + - FILES=$(find dist -name archive_name_\* -exec cat {} \+) + - cd dist + - scp ${FILES} ${HTTP_UPLOAD_DIR} + # Show info + - /bin/ls -l ${FILES} + - sha256sum ${FILES} + - echo -e "\nArchives were published there:\n\n$(for n in ${FILES}; do echo "${HTTP_PUBLIC_DIR}/${n}"; done)\n" diff --git a/configs/devices/riscv32-softmmu/default.mak b/configs/devices/riscv32-softmmu/default.mak index d847bd5692ec..2c0f262d91a1 100644 --- a/configs/devices/riscv32-softmmu/default.mak +++ b/configs/devices/riscv32-softmmu/default.mak @@ -13,3 +13,4 @@ CONFIG_SIFIVE_E=y CONFIG_SIFIVE_U=y CONFIG_RISCV_VIRT=y CONFIG_OPENTITAN=y +CONFIG_RISCV_ESP32C3=y diff --git a/configs/devices/xtensa-softmmu/default.mak b/configs/devices/xtensa-softmmu/default.mak index 4fe1bf00c94b..f819d9b781e2 100644 --- a/configs/devices/xtensa-softmmu/default.mak +++ b/configs/devices/xtensa-softmmu/default.mak @@ -7,3 +7,4 @@ CONFIG_SEMIHOSTING=y CONFIG_XTENSA_SIM=y CONFIG_XTENSA_VIRT=y CONFIG_XTENSA_XTFPGA=y +CONFIG_XTENSA_ESP32=y diff --git a/crypto/meson.build b/crypto/meson.build index 5f03a30d342d..8b6bcc6cc7c4 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -50,6 +50,11 @@ crypto_ss.add(when: gnutls, if_true: files('tls-cipher-suites.c')) util_ss.add(files('sm4.c')) util_ss.add(files('aes.c')) +util_ss.add(files('sha512-internal.c')) +util_ss.add(files('sha384-internal.c')) +util_ss.add(files('sha256-internal.c')) +util_ss.add(files('sha224-internal.c')) +util_ss.add(files('sha1-internal.c')) util_ss.add(files('init.c')) if gnutls.found() util_ss.add(gnutls) diff --git a/crypto/sha1-internal.c b/crypto/sha1-internal.c new file mode 100644 index 000000000000..a56d55c91b9a --- /dev/null +++ b/crypto/sha1-internal.c @@ -0,0 +1,227 @@ +/* + * SHA1 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "sha1_i.h" +#include "stddef.h" +#include "string.h" + +typedef struct sha1_state SHA1_CTX; + +/* ===== start - public domain SHA1 implementation ===== */ + +/* + * SHA-1 in C + * By Steve Reid + * 100% Public Domain + * + * ----------------- + * Modified 7/98 + * By James H. Brown + * Still 100% Public Domain + * + * Corrected a problem which generated improper hash values on 16 bit machines + * Routine SHA1Update changed from + * void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int + * len) + * to + * void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned + * long len) + * + * The 'len' parameter was declared an int which works fine on 32 bit machines. + * However, on 16 bit machines an int is too small for the shifts being done + * against + * it. This caused the hash function to generate incorrect values if len was + * greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). + * + * Since the file IO in main() reads 16K at a time, any file 8K or larger would + * be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million + * "a"s). + * + * I also changed the declaration of variables i & j in SHA1Update to + * unsigned long from unsigned int for the same reason. + * + * These changes should make no difference to any 32 bit implementations since + * an + * int and a long are the same size in those environments. + * + * -- + * I also corrected a few compiler warnings generated by Borland C. + * 1. Added #include for exit() prototype + * 2. Removed unused variable 'j' in SHA1Final + * 3. Changed exit(0) to return(0) at end of main. + * + * ALL changes I made can be located by searching for comments containing 'JHB' + * ----------------- + * Modified 8/98 + * By Steve Reid + * Still 100% public domain + * + * 1- Removed #include and used return() instead of exit() + * 2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) + * 3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net + * + * ----------------- + * Modified 4/01 + * By Saul Kravitz + * Still 100% PD + * Modified to run on Compaq Alpha hardware. + * + * ----------------- + * Modified 4/01 + * By Jouni Malinen + * Minor changes to match the coding style used in Dynamics. + * + * Modified September 24, 2004 + * By Jouni Malinen + * Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined. + * + */ + +/* + * Test Vectors (from FIPS PUB 180-1) + * "abc" + * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D + * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 + * A million repetitions of "a" + * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F + */ + +#define SHA1HANDSOFF + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifndef WORDS_BIGENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \ + (rol(block->l[i], 8) & 0x00FF00FF)) +#else +#define blk0(i) (block->l[i]) +#endif +#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ + block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v, w, x, y, z, i) \ + do { \ + z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); \ + } while (0) +#define R1(v, w, x, y, z, i) \ + do { \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); \ + } while (0) +#define R2(v, w, x, y, z, i) \ + do { \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ + w = rol(w, 30); \ + } while (0) +#define R3(v, w, x, y, z, i) \ + do { \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); \ + } while (0) +#define R4(v, w, x, y, z, i) \ + do { \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ + w = rol(w, 30); \ + } while (0) + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void sha1_compress(uint32_t state[5], const unsigned char buffer[64]) +{ + uint32_t a, b, c, d, e; + typedef union { + unsigned char c[64]; + uint32_t l[16]; + } CHAR64LONG16; + CHAR64LONG16 *block; +#ifdef SHA1HANDSOFF + CHAR64LONG16 workspace; + block = &workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16 *) buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a, b, c, d, e, 0); R0(e, a, b, c, d, 1); + R0(d, e, a, b, c, 2); R0(c, d, e, a, b, 3); + R0(b, c, d, e, a, 4); R0(a, b, c, d, e, 5); + R0(e, a, b, c, d, 6); R0(d, e, a, b, c, 7); + R0(c, d, e, a, b, 8); R0(b, c, d, e, a, 9); + R0(a, b, c, d, e, 10); R0(e, a, b, c, d, 11); + R0(d, e, a, b, c, 12); R0(c, d, e, a, b, 13); + R0(b, c, d, e, a, 14); R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); R1(d, e, a, b, c, 17); + R1(c, d, e, a, b, 18); R1(b, c, d, e, a, 19); + R2(a, b, c, d, e, 20); R2(e, a, b, c, d, 21); + R2(d, e, a, b, c, 22); R2(c, d, e, a, b, 23); + R2(b, c, d, e, a, 24); R2(a, b, c, d, e, 25); + R2(e, a, b, c, d, 26); R2(d, e, a, b, c, 27); + R2(c, d, e, a, b, 28); R2(b, c, d, e, a, 29); + R2(a, b, c, d, e, 30); R2(e, a, b, c, d, 31); + R2(d, e, a, b, c, 32); R2(c, d, e, a, b, 33); + R2(b, c, d, e, a, 34); R2(a, b, c, d, e, 35); + R2(e, a, b, c, d, 36); R2(d, e, a, b, c, 37); + R2(c, d, e, a, b, 38); R2(b, c, d, e, a, 39); + R3(a, b, c, d, e, 40); R3(e, a, b, c, d, 41); + R3(d, e, a, b, c, 42); R3(c, d, e, a, b, 43); + R3(b, c, d, e, a, 44); R3(a, b, c, d, e, 45); + R3(e, a, b, c, d, 46); R3(d, e, a, b, c, 47); + R3(c, d, e, a, b, 48); R3(b, c, d, e, a, 49); + R3(a, b, c, d, e, 50); R3(e, a, b, c, d, 51); + R3(d, e, a, b, c, 52); R3(c, d, e, a, b, 53); + R3(b, c, d, e, a, 54); R3(a, b, c, d, e, 55); + R3(e, a, b, c, d, 56); R3(d, e, a, b, c, 57); + R3(c, d, e, a, b, 58); R3(b, c, d, e, a, 59); + R4(a, b, c, d, e, 60); R4(e, a, b, c, d, 61); + R4(d, e, a, b, c, 62); R4(c, d, e, a, b, 63); + R4(b, c, d, e, a, 64); R4(a, b, c, d, e, 65); + R4(e, a, b, c, d, 66); R4(d, e, a, b, c, 67); + R4(c, d, e, a, b, 68); R4(b, c, d, e, a, 69); + R4(a, b, c, d, e, 70); R4(e, a, b, c, d, 71); + R4(d, e, a, b, c, 72); R4(c, d, e, a, b, 73); + R4(b, c, d, e, a, 74); R4(a, b, c, d, e, 75); + R4(e, a, b, c, d, 76); R4(d, e, a, b, c, 77); + R4(c, d, e, a, b, 78); R4(b, c, d, e, a, 79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +#ifdef SHA1HANDSOFF + memset(block, 0, 64); +#endif +} + +/* sha1_init - Initialize new context */ + +void sha1_init(SHA1_CTX *context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + +/* ===== end - public domain SHA1 implementation ===== */ diff --git a/crypto/sha1_i.h b/crypto/sha1_i.h new file mode 100644 index 000000000000..b91211fce6e3 --- /dev/null +++ b/crypto/sha1_i.h @@ -0,0 +1,21 @@ +/* + * SHA1 internal definitions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef SHA1_I_H +#define SHA1_I_H +#include "qemu/osdep.h" + +struct sha1_state { + uint32_t state[5]; + uint32_t count[2]; +}; + +void sha1_init(struct sha1_state *context); +void sha1_compress(uint32_t state[5], const unsigned char buffer[64]); + +#endif /* SHA1_I_H */ diff --git a/crypto/sha224-internal.c b/crypto/sha224-internal.c new file mode 100644 index 000000000000..98501f28bf9c --- /dev/null +++ b/crypto/sha224-internal.c @@ -0,0 +1,30 @@ +/* + * SHA-224 hash implementation and interface functions + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "sha224_i.h" + + +int sha224_compress(sha224_state *md, unsigned char *buf) +{ + return sha256_compress(md, buf); +} + + +void sha224_init(sha224_state *md) +{ + /** + * Initial values for SHA224 algorithm + */ + md->state[0] = 0xC1059ED8UL; + md->state[1] = 0x367CD507UL; + md->state[2] = 0x3070DD17UL; + md->state[3] = 0xF70E5939UL; + md->state[4] = 0xFFC00B31UL; + md->state[5] = 0x68581511UL; + md->state[6] = 0x64F98FA7UL; + md->state[7] = 0xBEFA4FA4UL; +} diff --git a/crypto/sha224_i.h b/crypto/sha224_i.h new file mode 100644 index 000000000000..e4c58f3fbd07 --- /dev/null +++ b/crypto/sha224_i.h @@ -0,0 +1,24 @@ +/* + * SHA-224 internal definitions + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef SHA224_I_H +#define SHA224_I_H + +#include "qemu/osdep.h" +#include "sha256_i.h" + +/** + * @brief Size of SHA224 hash in bytes + */ +#define SHA224_HASH_SIZE 28 + +typedef struct sha256_state sha224_state; + +void sha224_init(sha224_state *md); +int sha224_compress(sha224_state *md, unsigned char *buf); + +#endif /* SHA224_I_H */ diff --git a/crypto/sha256-internal.c b/crypto/sha256-internal.c new file mode 100644 index 000000000000..708269eb1187 --- /dev/null +++ b/crypto/sha256-internal.c @@ -0,0 +1,107 @@ +/* + * SHA-256 hash implementation and interface functions + * Copyright (c) 2003-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "sha256_i.h" + +static inline uint32_t WPA_GET_BE32(const uint8_t *a) +{ + return ((uint32_t) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]; +} + +/* ===== start - public domain SHA256 implementation ===== */ + +/* + * This is based on SHA256 implementation in LibTomCrypt that was released into + * public domain by Tom St Denis. + */ + +/* the K array */ +static const unsigned long K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Compress */ +#define RND(a, b, c, d, e, f, g, h, i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; +/* Various logical functions */ +#define RORc(x, y) \ +(((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ + ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) +#define Ch(x, y, z) (z ^ (x & (y ^ z))) +#define Maj(x, y, z) (((x | y) & z) | (x & y)) +#define S(x, n) RORc((x), (n)) +#define R(x, n) (((x) & 0xFFFFFFFFUL) >> (n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) + +/* compress 512-bits */ +int sha256_compress(struct sha256_state *md, unsigned char *buf) +{ + uint32_t S[8], W[64], t0, t1; + uint32_t t; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) { + S[i] = md->state[i]; + } + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + W[i] = WPA_GET_BE32(buf + (4 * i)); + } + /* fill W[16..63] */ + for (i = 16; i < 64; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + + W[i - 16]; + } + + for (i = 0; i < 64; ++i) { + RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); + t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; + S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; + } + + /* feedback */ + for (i = 0; i < 8; i++) { + md->state[i] = md->state[i] + S[i]; + } + return 0; +} + +/* Initialize the hash state */ +void sha256_init(struct sha256_state *md) +{ + md->state[0] = 0x6A09E667UL; + md->state[1] = 0xBB67AE85UL; + md->state[2] = 0x3C6EF372UL; + md->state[3] = 0xA54FF53AUL; + md->state[4] = 0x510E527FUL; + md->state[5] = 0x9B05688CUL; + md->state[6] = 0x1F83D9ABUL; + md->state[7] = 0x5BE0CD19UL; +} + +/* ===== end - public domain SHA256 implementation ===== */ diff --git a/crypto/sha256_i.h b/crypto/sha256_i.h new file mode 100644 index 000000000000..50d23ec55513 --- /dev/null +++ b/crypto/sha256_i.h @@ -0,0 +1,20 @@ +/* + * SHA-256 internal definitions + * Copyright (c) 2003-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef SHA256_I_H +#define SHA256_I_H +#include "qemu/osdep.h" + +struct sha256_state { + uint32_t state[8]; +}; + +void sha256_init(struct sha256_state *md); +int sha256_compress(struct sha256_state *md, unsigned char *buf); + +#endif /* SHA256_I_H */ diff --git a/crypto/sha384-internal.c b/crypto/sha384-internal.c new file mode 100644 index 000000000000..1a0e6f807416 --- /dev/null +++ b/crypto/sha384-internal.c @@ -0,0 +1,37 @@ +/* + * SHA-384 hash implementation and interface functions + * Copyright (c) 2015, Pali Rohár + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "sha384_i.h" + +/* ===== start - public domain SHA384 implementation ===== */ + +/* + * This is based on SHA384 implementation in LibTomCrypt that was released into + * public domain by Tom St Denis. + */ + +#define CONST64(n) n ## ULL + +/* + * Initialize the hash state + * @param md The hash state you wish to initialize + * @return CRYPT_OK if successful + */ +void sha384_init(struct sha512_state *md) +{ + md->state[0] = CONST64(0xcbbb9d5dc1059ed8); + md->state[1] = CONST64(0x629a292a367cd507); + md->state[2] = CONST64(0x9159015a3070dd17); + md->state[3] = CONST64(0x152fecd8f70e5939); + md->state[4] = CONST64(0x67332667ffc00b31); + md->state[5] = CONST64(0x8eb44a8768581511); + md->state[6] = CONST64(0xdb0c2e0d64f98fa7); + md->state[7] = CONST64(0x47b5481dbefa4fa4); +} + +/* ===== end - public domain SHA384 implementation ===== */ diff --git a/crypto/sha384_i.h b/crypto/sha384_i.h new file mode 100644 index 000000000000..e8f9793af070 --- /dev/null +++ b/crypto/sha384_i.h @@ -0,0 +1,19 @@ +/* + * SHA-384 internal definitions + * Copyright (c) 2015, Pali Rohár + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef SHA384_I_H +#define SHA384_I_H + +#include "qemu/osdep.h" +#include "sha512_i.h" + +#define sha384_state sha512_state + +void sha384_init(struct sha384_state *md); + +#endif /* SHA384_I_H */ diff --git a/crypto/sha512-internal.c b/crypto/sha512-internal.c new file mode 100644 index 000000000000..9ee72afb745a --- /dev/null +++ b/crypto/sha512-internal.c @@ -0,0 +1,148 @@ +/* + * SHA-512 hash implementation and interface functions + * Copyright (c) 2015, Pali Rohár + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "sha512_i.h" + +static inline uint64_t WPA_GET_BE64(const uint8_t *a) +{ + return (((uint64_t) a[0]) << 56) | (((uint64_t) a[1]) << 48) | + (((uint64_t) a[2]) << 40) | (((uint64_t) a[3]) << 32) | + (((uint64_t) a[4]) << 24) | (((uint64_t) a[5]) << 16) | + (((uint64_t) a[6]) << 8) | ((uint64_t) a[7]); +} + +/* ===== start - public domain SHA512 implementation ===== */ + +/* + * This is based on SHA512 implementation in LibTomCrypt that was released into + * public domain by Tom St Denis. + */ + +#define CONST64(n) n ## ULL + +/* the K array */ +static const uint64_t K[80] = { + CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd), + CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc), + CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019), + CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118), + CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe), + CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2), + CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1), + CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694), + CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3), + CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65), + CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483), + CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5), + CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210), + CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4), + CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725), + CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70), + CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926), + CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df), + CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8), + CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b), + CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001), + CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30), + CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910), + CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8), + CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53), + CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8), + CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb), + CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3), + CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60), + CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec), + CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9), + CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b), + CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207), + CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178), + CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6), + CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b), + CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493), + CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c), + CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a), + CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817) +}; + +/* Various logical functions */ +#define Ch(x, y, z) (z ^ (x & (y ^ z))) +#define Maj(x, y, z) (((x | y) & z) | (x & y)) +#define S(x, n) ROR64c(x, n) +#define R(x, n) (((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t) n)) +#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) +#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) +#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) +#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) + +#define ROR64c(x, y) \ + (((((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t) (y) & CONST64(63))) | \ + ((x) << ((uint64_t) (64 - ((y) & CONST64(63)))))) & \ + CONST64(0xFFFFFFFFFFFFFFFF)) + +/* compress 1024-bits */ +int sha512_compress(struct sha512_state *md, unsigned char *buf) +{ + uint64_t S[8], t0, t1; + uint64_t W[80]; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) { + S[i] = md->state[i]; + } + + /* copy the state into 1024-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + W[i] = WPA_GET_BE64(buf + (8 * i)); + } + /* fill W[16..79] */ + for (i = 16; i < 80; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + + W[i - 16]; + } + + /* Compress */ + for (i = 0; i < 80; i++) { + t0 = S[7] + Sigma1(S[4]) + Ch(S[4], S[5], S[6]) + K[i] + W[i]; + t1 = Sigma0(S[0]) + Maj(S[0], S[1], S[2]); + S[7] = S[6]; + S[6] = S[5]; + S[5] = S[4]; + S[4] = S[3] + t0; + S[3] = S[2]; + S[2] = S[1]; + S[1] = S[0]; + S[0] = t0 + t1; + } + + /* feedback */ + for (i = 0; i < 8; i++) { + md->state[i] = md->state[i] + S[i]; + } + + return 0; +} + +/* + * Initialize the hash state + * @param md The hash state you wish to initialize + * @return CRYPT_OK if successful + */ +void sha512_init(struct sha512_state *md) +{ + md->state[0] = CONST64(0x6a09e667f3bcc908); + md->state[1] = CONST64(0xbb67ae8584caa73b); + md->state[2] = CONST64(0x3c6ef372fe94f82b); + md->state[3] = CONST64(0xa54ff53a5f1d36f1); + md->state[4] = CONST64(0x510e527fade682d1); + md->state[5] = CONST64(0x9b05688c2b3e6c1f); + md->state[6] = CONST64(0x1f83d9abfb41bd6b); + md->state[7] = CONST64(0x5be0cd19137e2179); +} + +/* ===== end - public domain SHA512 implementation ===== */ diff --git a/crypto/sha512_i.h b/crypto/sha512_i.h new file mode 100644 index 000000000000..a669e6fd1222 --- /dev/null +++ b/crypto/sha512_i.h @@ -0,0 +1,20 @@ +/* + * SHA-512 internal definitions + * Copyright (c) 2015, Pali Rohár + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef SHA512_I_H +#define SHA512_I_H +#include "qemu/osdep.h" + +struct sha512_state { + uint64_t state[8]; +}; + +void sha512_init(struct sha512_state *md); +int sha512_compress(struct sha512_state *md, unsigned char *buf); + +#endif /* SHA512_I_H */ diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index dc5ffbc4ff52..6815553df083 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -171,6 +171,8 @@ typedef struct FlashPartInfo { #define SPANSION_CONTINUOUS_READ_MODE_CMD_LEN 1 #define WINBOND_CONTINUOUS_READ_MODE_CMD_LEN 1 +#define GIGADEVICE_CONTINUOUS_READ_MODE_CMD_LEN 1 + static const FlashPartInfo known_devices[] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ @@ -445,6 +447,7 @@ typedef enum { MAN_WINBOND, MAN_SST, MAN_ISSI, + MAN_GIGADEVICE, MAN_GENERIC, } Manufacturer; @@ -529,6 +532,8 @@ static inline Manufacturer get_man(Flash *s) return MAN_SST; case 0x9D: return MAN_ISSI; + case 0xC8: + return MAN_GIGADEVICE; default: return MAN_GENERIC; } @@ -1014,6 +1019,9 @@ static void decode_dio_read_cmd(Flash *s) case MAN_WINBOND: s->needed_bytes += WINBOND_CONTINUOUS_READ_MODE_CMD_LEN; break; + case MAN_GIGADEVICE: + s->needed_bytes += GIGADEVICE_CONTINUOUS_READ_MODE_CMD_LEN; + break; case MAN_SPANSION: s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN; s->needed_bytes += extract32(s->spansion_cr2v, @@ -1061,6 +1069,7 @@ static void decode_qio_read_cmd(Flash *s) /* Dummy cycles modeled with bytes writes instead of bits */ switch (get_man(s)) { case MAN_WINBOND: + case MAN_GIGADEVICE: s->needed_bytes += WINBOND_CONTINUOUS_READ_MODE_CMD_LEN; s->needed_bytes += 4; break; diff --git a/hw/char/esp32_uart.c b/hw/char/esp32_uart.c new file mode 100644 index 000000000000..311a07764239 --- /dev/null +++ b/hw/char/esp32_uart.c @@ -0,0 +1,408 @@ +/* + * ESP32 UART emulation + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * The QEMU model of nRF51 UART by Julia Suvorova was used as a template. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "sysemu/sysemu.h" +#include "chardev/char-fe.h" +#include "hw/registerfields.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "hw/char/esp32_uart.h" +#include "trace.h" + + +static gboolean uart_transmit(void *do_not_use, GIOCondition cond, void *opaque); +static void uart_receive(void *opaque, const uint8_t *buf, int size); +static void uart_set_rx_timeout(ESP32UARTState *s); + +static uint8_t fifo8_peek(Fifo8 *fifo) +{ + if (fifo->num == 0) { + abort(); + } + return fifo->data[fifo->head]; +} + +static void uart_update_irq(ESP32UARTState *s) +{ + bool irq = false; + + uint32_t tx_empty_threshold = FIELD_EX32(s->reg[R_UART_CONF1], UART_CONF1, TXFIFO_EMPTY_THRD); + uint32_t rx_full_threshold = FIELD_EX32(s->reg[R_UART_CONF1], UART_CONF1, RXFIFO_FULL_THRD); + + uint32_t tx_empty_raw = (fifo8_num_used(&s->tx_fifo) <= tx_empty_threshold); + uint32_t rx_full_raw = (fifo8_num_used(&s->rx_fifo) >= rx_full_threshold); + uint32_t tx_done_raw = (fifo8_num_used(&s->tx_fifo) == 0); + uint32_t rxfifo_tout_raw = (s->rxfifo_tout) ? 1 : 0; + + uint32_t int_raw = s->reg[R_UART_INT_RAW]; + int_raw = FIELD_DP32(int_raw, UART_INT_RAW, RXFIFO_FULL, rx_full_raw); + int_raw = FIELD_DP32(int_raw, UART_INT_RAW, TXFIFO_EMPTY, tx_empty_raw); + int_raw = FIELD_DP32(int_raw, UART_INT_RAW, TX_DONE, tx_done_raw); + int_raw = FIELD_DP32(int_raw, UART_INT_RAW, RXFIFO_TOUT, rxfifo_tout_raw); + s->reg[R_UART_INT_RAW] = int_raw; + + uint32_t int_st = s->reg[R_UART_INT_RAW] & s->reg[R_UART_INT_ENA]; + irq = int_st != 0; + s->reg[R_UART_INT_ST] = int_st; + + qemu_set_irq(s->irq, irq); +} + +static uint64_t uart_read(void *opaque, hwaddr addr, unsigned int size) +{ + ESP32UARTState *s = ESP32_UART(opaque); + uint64_t r = 0; + + switch (addr) { + case A_UART_FIFO: + if (fifo8_num_used(&s->rx_fifo) == 0) { + r = 0xEE; + error_report("esp_uart: read UART FIFO while it is empty"); + } else { + r = fifo8_pop(&s->rx_fifo); + uart_update_irq(s); + qemu_chr_fe_accept_input(&s->chr); + } + break; + + case A_UART_STATUS: + r = FIELD_DP32(r, UART_STATUS, RXFIFO_CNT, fifo8_num_used(&s->rx_fifo)); + r = FIELD_DP32(r, UART_STATUS, TXFIFO_CNT, fifo8_num_used(&s->tx_fifo)); + break; + + case A_UART_LOWPULSE: + case A_UART_HIGHPULSE: + r = 337; /* FIXME: this should depend on the APB frequency */ + break; + case A_UART_MEM_CONF: + r = FIELD_DP32(r, UART_MEM_CONF, RX_SIZE, (unsigned char)(UART_FIFO_LENGTH/128)); + r = FIELD_DP32(r, UART_MEM_CONF, TX_SIZE, (unsigned char)(UART_FIFO_LENGTH/128)); + break; + case A_UART_MEM_RX_STATUS: { + uint32_t fifo_size = fifo8_num_used(&s->rx_fifo); + /* The software only cares about the differene between WR_ADDR and RD_ADDR; + * to keep things simpler, set RD_ADDR to 0 and WR_ADDR to the number of bytes + * in the FIFO. 128 is a special case — write and read pointers should be + * the same in this case. + */ + r = FIELD_DP32(0, UART_MEM_RX_STATUS, WR_ADDR, (fifo_size == 128) ? 0 : fifo_size); + } + break; + case A_UART_DATE: + r = 0x15122500; + break; + default: + r = s->reg[addr / 4]; + break; + } + + return r; +} + + +static void uart_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + ESP32UARTState *s = ESP32_UART(opaque); + + switch (addr) { + case A_UART_FIFO: + if (fifo8_num_free(&s->tx_fifo) == 0) { + error_report("esp_uart: write to UART FIFO while it is full"); + } else { + fifo8_push(&s->tx_fifo, (uint8_t) (value & 0xff)); + uart_transmit(NULL, G_IO_OUT, s); + } + break; + + case A_UART_INT_CLR: + s->reg[R_UART_INT_ST] &= ~((uint32_t) value); + s->reg[addr / 4] = value; + if (value & R_UART_INT_CLR_RXFIFO_TOUT_MASK) { + s->rxfifo_tout = false; + } + break; + + case A_UART_INT_ENA: + s->reg[addr / 4] = value; + break; + + case A_UART_CLKDIV: { + s->reg[addr / 4] = value; + unsigned clkdiv = (FIELD_EX32(s->reg[R_UART_CLKDIV], UART_CLKDIV, CLKDIV) << 4) + + FIELD_EX32(s->reg[R_UART_CLKDIV], UART_CLKDIV, CLKDIV_FRAG); + unsigned baud_rate = 115200; + if (clkdiv != 0) { + /* FIXME: this should depend on the APB frequency */ + baud_rate = (unsigned) ((40000000ULL << 4) / clkdiv); + } + s->baud_rate = baud_rate; + break; + } + + case A_UART_AUTOBAUD: + /* If autobaud is enabled, pretend that sufficient number of edges on the RXD line + * have been received instantly. Autobaud is only used in the ROM bootloader, + * and it doesn't care if the result is ready immediately. + */ + if (FIELD_EX32(value, UART_AUTOBAUD, EN)) { + s->reg[R_UART_RXD_CNT] = 0x3FF; + } else { + s->reg[R_UART_RXD_CNT] = 0; + } + s->reg[addr / 4] = value; + break; + + case A_UART_INT_RAW: + case A_UART_INT_ST: + case A_UART_STATUS: + /* no-op */ + break; + + case A_UART_CONF1: + s->reg[addr / 4] = value; + uart_set_rx_timeout(s); + uart_update_irq(s); + break; + + default: + if (addr > sizeof(s->reg)) { + error_report("esp_uart: write to addr=0x%x out of bounds\n", (uint32_t) addr); + } else { + s->reg[addr / 4] = value; + } + break; + + } + uart_update_irq(s); +} + + +static gboolean uart_transmit(void *do_not_use, GIOCondition cond, void *opaque) +{ + ESP32UARTState *s = ESP32_UART(opaque); + + s->tx_watch_handle = 0; + + /* drain the fifo instantly, if the char device backend is not connected */ + if (!qemu_chr_fe_backend_open(&s->chr)) { + fifo8_reset(&s->tx_fifo); + return FALSE; + } + + while (fifo8_num_used(&s->tx_fifo) > 0) { + uint8_t b = fifo8_peek(&s->tx_fifo); + int r = qemu_chr_fe_write(&s->chr, &b, 1); + if (r == 1) { + fifo8_pop(&s->tx_fifo); + } else { + s->tx_watch_handle = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP, + uart_transmit, s); + break; + } + } + + uart_update_irq(s); + + return FALSE; +} + +static void uart_receive(void *opaque, const uint8_t *buf, int size) +{ + ESP32UARTState *s = ESP32_UART(opaque); + + if (size == 0) { + return; + } + + /* If we can receive anything: cancel any pending RX timeout timer, + * and clear the receive timeout flag. + */ + if (fifo8_num_free(&s->rx_fifo) > 0) { + timer_del(&s->rx_timeout_timer); + s->rxfifo_tout = false; + } + + /* Move the data into the FIFO */ + for (int i = 0; i < size && fifo8_num_free(&s->rx_fifo) > 0; i++) { + fifo8_push(&s->rx_fifo, buf[i]); + } + + /* Receive throttling: some applications (in particular the ESP32 ROM bootloader) + * may work incorrectly if the data comes in much faster than what UART baud rate + * would allow. This code adds a delay every UART_FIFO_LENGTH bytes, to make the + * average data rate match the configured baud rate. + * This doesn't need to be very precise, so only add the delay if the FIFO is full + * (which most likely means that more data will come). + */ + if (fifo8_is_full(&s->rx_fifo)) { + s->throttle_rx = true; + const int bits_per_symbol = 10; + int64_t throttle_time_ns = (int64_t) UART_FIFO_LENGTH * bits_per_symbol * NANOSECONDS_PER_SECOND / s->baud_rate; + timer_mod_ns(&s->throttle_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + throttle_time_ns); + } + + uart_set_rx_timeout(s); + uart_update_irq(s); +} + +static void uart_set_rx_timeout(ESP32UARTState *s) +{ + if (FIELD_EX32(s->reg[R_UART_CONF1], UART_CONF1, TOUT_EN)) { + unsigned threshold_reg = FIELD_EX32(s->reg[R_UART_CONF1], UART_CONF1, TOUT_THRD); + /* On the ESP32, threshold_reg is in units of (bit_time * 8). + * Note this is different on later chips. + */ + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + int64_t rx_timeout_ns = now + threshold_reg * 8 * NANOSECONDS_PER_SECOND / s->baud_rate; + /* If throttling is done, make sure timeout doesn't happen before more data + * is allowed to come. Offset it by 1ms. + */ + if (rx_timeout_ns <= s->throttle_timer.expire_time) { + rx_timeout_ns = s->throttle_timer.expire_time + 10000000; + } + timer_mod_ns(&s->rx_timeout_timer, rx_timeout_ns); + } else { + timer_del(&s->rx_timeout_timer); + s->rxfifo_tout = false; + } +} + +static int uart_can_receive(void *opaque) +{ + ESP32UARTState *s = ESP32_UART(opaque); + if (s->throttle_rx) { + return 0; + } + return fifo8_num_free(&s->rx_fifo); +} + +static void uart_event(void *opaque, QEMUChrEvent event) +{ + /* TODO: handle UART break */ +} + + +static void uart_throttle_timer_cb(void* opaque) +{ + ESP32UARTState *s = ESP32_UART(opaque); + s->throttle_rx = false; + qemu_chr_fe_accept_input(&s->chr); +} + +static void uart_rx_timeout_timer_cb(void* opaque) +{ + ESP32UARTState *s = ESP32_UART(opaque); + s->rxfifo_tout = true; + uart_update_irq(s); +} + +static void esp32_uart_reset(DeviceState *dev) +{ + ESP32UARTState *s = ESP32_UART(dev); + + memset(s->reg, 0, sizeof(s->reg)); + s->reg[R_UART_RXD_CNT] = 0; + s->reg[R_UART_INT_ST] = 0; + s->reg[R_UART_INT_RAW] = 0; + s->reg[R_UART_INT_ENA] = 0; + s->reg[R_UART_AUTOBAUD] = 0; + /* Default baud rate divider after reset */ + s->reg[R_UART_CLKDIV] = FIELD_DP32(0, UART_CLKDIV, CLKDIV, 0x2B6); + s->baud_rate = 115200; + fifo8_reset(&s->tx_fifo); + fifo8_reset(&s->rx_fifo); + if (s->tx_watch_handle) { + g_source_remove(s->tx_watch_handle); + s->tx_watch_handle = 0; + } + timer_del(&s->throttle_timer); + s->throttle_rx = false; + qemu_irq_lower(s->irq); +} + + +static void esp32_uart_realize(DeviceState *dev, Error **errp) +{ + ESP32UARTState *s = ESP32_UART(dev); + + qemu_chr_fe_set_handlers(&s->chr, uart_can_receive, uart_receive, + uart_event, NULL, s, NULL, true); +} + + +static void esp32_uart_init(Object *obj) +{ + ESP32UARTState *s = ESP32_UART(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + ESP32UARTClass *class = ESP32_UART_GET_CLASS(obj); + + s->uart_ops = (MemoryRegionOps) { + .read = class->uart_read, + .write = class->uart_write, + .endianness = DEVICE_LITTLE_ENDIAN, + }; + + memory_region_init_io(&s->iomem, obj, &s->uart_ops, s, + TYPE_ESP32_UART, UART_REG_CNT * sizeof(uint32_t)); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + fifo8_create(&s->tx_fifo, UART_FIFO_LENGTH); + fifo8_create(&s->rx_fifo, UART_FIFO_LENGTH); + timer_init_ns(&s->throttle_timer, QEMU_CLOCK_VIRTUAL, uart_throttle_timer_cb, s); + timer_init_ns(&s->rx_timeout_timer, QEMU_CLOCK_VIRTUAL, uart_rx_timeout_timer_cb, s); +} + + +static Property esp32_uart_properties[] = { + DEFINE_PROP_CHR("chardev", ESP32UARTState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32_uart_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ESP32UARTClass *class = ESP32_UART_CLASS(klass); + + /* Populate the virtual attributes and methods here (if any) */ + class->uart_write = uart_write; + class->uart_read = uart_read; + + dc->reset = esp32_uart_reset; + dc->realize = esp32_uart_realize; + device_class_set_props(dc, esp32_uart_properties); +} + +static const TypeInfo esp32_uart_info = { + .name = TYPE_ESP32_UART, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32UARTState), + .instance_init = esp32_uart_init, + .class_init = esp32_uart_class_init, + .class_size = sizeof(ESP32UARTClass) +}; + +static void esp32_uart_register_types(void) +{ + type_register_static(&esp32_uart_info); +} + +type_init(esp32_uart_register_types) diff --git a/hw/char/esp32c3_uart.c b/hw/char/esp32c3_uart.c new file mode 100644 index 000000000000..029aeda1f1e0 --- /dev/null +++ b/hw/char/esp32c3_uart.c @@ -0,0 +1,118 @@ +/* + * ESP32C3 UART emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This implementation overrides the ESP32 UARt one, check it out first. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/char/esp32c3_uart.h" +#include "hw/misc/esp32c3_rtc_cntl.h" + +#define ESP32_UART_AUTOBAUD A_UART_AUTOBAUD + +static uint64_t esp32c3_uart_read(void *opaque, hwaddr addr, unsigned int size) +{ + ESP32C3UARTClass *class = ESP32C3_UART_GET_CLASS(opaque); + /* Nothing special to do at the moment here, but it is possible to override the + * parent's read function behavior. */ + + return class->parent_uart_read(opaque, addr, size); +} + +static void esp32c3_uart_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + ESP32C3UARTClass *class = ESP32C3_UART_GET_CLASS(opaque); + uint32_t autobaud = 0; + + /* UART_RXD_CNT_REG register is not at the same address on the ESP32 and ESP32-C3, so make the + * the translation here. */ + switch (addr) { + + case A_ESP32C3_UART_CONF0: + /* On the C3, AUTOBAUD is part of CONF0 register, but on the ESP32, it has its own + * register, poke that register instead */ + autobaud = FIELD_EX32(value, ESP32C3_UART_CONF0, AUTOBAUD_EN) ? 1 : 0; + class->parent_uart_write(opaque, ESP32_UART_AUTOBAUD, autobaud, sizeof(uint32_t)); + /* CONF0 is still a valid register on the ESP32, so fall-through the default case*/ + + default: + class->parent_uart_write(opaque, addr, value, size); + break; + + } +} + +static void esp32c3_uart_reset(DeviceState *dev) +{ + /* Nothing special to do at the moment here, call the parent reset */ + ESP32C3UARTClass* esp32c3_class = ESP32C3_UART_GET_CLASS(dev); + + esp32c3_class->parent_reset(dev); +} + +static void esp32c3_uart_realize(DeviceState *dev, Error **errp) +{ + // ESP32C3UARTState* esp32c3 = ESP32C3_UART(dev); + ESP32C3UARTClass* esp32c3_class = ESP32C3_UART_GET_CLASS(dev); + + /* Call the realize function of the parent class: ESP32UARTClass */ + esp32c3_class->parent_realize(dev, errp); +} + + +static void esp32c3_uart_init(Object *obj) +{ + /* No need to call parent's class function, this is done automatically by the QOM, even before + * calling the current function. */ +} + + +static void esp32c3_uart_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ESP32C3UARTClass* esp32c3 = ESP32C3_UART_CLASS(klass); + ESP32UARTClass* esp32 = ESP32_UART_CLASS(klass); + + /* Set our class' parent_realize field to the current realize function, set by the + * parent class initializer. + * After doing this, it will be necessary for our function, esp32c3_uart_realize, + * to manually call the parent's one. */ + device_class_set_parent_realize(dc, esp32c3_uart_realize, &esp32c3->parent_realize); + + /* Let's do the same thing for the reset function */ + device_class_set_parent_reset(dc, esp32c3_uart_reset, &esp32c3->parent_reset); + + /* Override the UART operations functions */ + esp32c3->parent_uart_write = esp32->uart_write; + esp32c3->parent_uart_read = esp32->uart_read; + esp32->uart_write = esp32c3_uart_write; + esp32->uart_read = esp32c3_uart_read; +} + +static const TypeInfo esp32c3_uart_info = { + .name = TYPE_ESP32C3_UART, + .parent = TYPE_ESP32_UART, + .instance_size = sizeof(ESP32C3UARTState), + .instance_init = esp32c3_uart_init, + .class_init = esp32c3_uart_class_init, + .class_size = sizeof(ESP32C3UARTClass) +}; + +static void esp32c3_uart_register_types(void) +{ + type_register_static(&esp32c3_uart_info); +} + +type_init(esp32c3_uart_register_types) diff --git a/hw/char/meson.build b/hw/char/meson.build index e02c60dd54d9..5123262053c2 100644 --- a/hw/char/meson.build +++ b/hw/char/meson.build @@ -32,6 +32,8 @@ softmmu_ss.add(when: 'CONFIG_SIFIVE_UART', if_true: files('sifive_uart.c')) softmmu_ss.add(when: 'CONFIG_SH_SCI', if_true: files('sh_serial.c')) softmmu_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_usart.c')) softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_MMUART', if_true: files('mchp_pfsoc_mmuart.c')) +softmmu_ss.add(when: 'CONFIG_XTENSA_ESP32', if_true: files('esp32_uart.c')) +softmmu_ss.add(when: 'CONFIG_RISCV_ESP32C3', if_true: files('esp32_uart.c', 'esp32c3_uart.c')) specific_ss.add(when: 'CONFIG_HTIF', if_true: files('riscv_htif.c')) specific_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('terminal3270.c')) diff --git a/hw/dma/esp32c3_gdma.c b/hw/dma/esp32c3_gdma.c new file mode 100644 index 000000000000..98c2c6a7f9b0 --- /dev/null +++ b/hw/dma/esp32c3_gdma.c @@ -0,0 +1,1038 @@ +/* + * ESP32-C3 GDMA emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "sysemu/dma.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/dma/esp32c3_gdma.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "qemu/error-report.h" + +#define GDMA_WARNING 0 +#define GDMA_DEBUG 0 + + +/** + * @brief Structure defining how linked lists are represented in hardware for the GDMA module + */ +typedef struct GdmaLinkedList { + union { + struct { + uint32_t size: 12; // Size of the buffer (mainly used in a receive transaction) + uint32_t length: 12; // Number of valid bytes in the buffer. In a transmit, written by software. + // In receive, written by hardware. + uint32_t rsvd_24: 4; // Reserved + uint32_t err_eof: 1; // Set if received data has errors. Used with UHCI0 only. + uint32_t rsvd_29: 1; // Reserved + uint32_t suc_eof: 1; // Set if curent node is the last one (of the list). Set by software in a transmit transaction, + // Set by the hardware in case of a receive transaction. + uint32_t owner: 1; // 0: CPU can access the buffer, 1: GDMA can access the buffer. Cleared automatically + // by hardware in a transmit descriptor. In a receive descriptor, cleared by hardware + // only if GDMA_OUT_AUTO_WRBACK_CHn is set to 1. + }; + uint32_t val; + } config; + uint32_t buf_addr; + uint32_t next_addr; +} GdmaLinkedList; + + +static uint32_t read_addr_word(uint32_t* ptr, uint32_t offset) { + return ptr[offset / sizeof(uint32_t)]; +} + + +static uint64_t esp32c3_gdma_read(void *opaque, hwaddr addr, unsigned int size) +{ + ESP32C3GdmaState *s = ESP32C3_GDMA(opaque); + uint64_t r = 0; + + + switch(addr) { + case A_DMA_INT_RAW_CH0 ... A_DMA_INT_CLR_CH2: + r = read_addr_word((uint32_t*) s->ch_int, addr - A_DMA_INT_RAW_CH0); + break; + + case A_DMA_MISC_CONF: + r = s->misc_conf; + break; + + case A_DMA_IN_CONF0_CH0 ... A_DMA_IN_PERI_SEL_CH0: + r = read_addr_word((uint32_t*) &s->ch_conf[0][ESP32C3_GDMA_IN_IDX], addr - A_DMA_IN_CONF0_CH0); + break; + + case A_DMA_OUT_CONF0_CH0 ... A_DMA_OUT_PERI_SEL_CH0: + r = read_addr_word((uint32_t*) &s->ch_conf[0][ESP32C3_GDMA_OUT_IDX], addr - A_DMA_OUT_CONF0_CH0); + break; + + case A_DMA_IN_CONF0_CH1 ... A_DMA_IN_PERI_SEL_CH1: + r = read_addr_word((uint32_t*) &s->ch_conf[1][ESP32C3_GDMA_IN_IDX], addr - A_DMA_IN_CONF0_CH1); + break; + + case A_DMA_OUT_CONF0_CH1 ... A_DMA_OUT_PERI_SEL_CH1: + r = read_addr_word((uint32_t*) &s->ch_conf[1][ESP32C3_GDMA_OUT_IDX], addr - A_DMA_OUT_CONF0_CH1); + break; + + case A_DMA_IN_CONF0_CH2 ... A_DMA_IN_PERI_SEL_CH2: + r = read_addr_word((uint32_t*) &s->ch_conf[2][ESP32C3_GDMA_IN_IDX], addr - A_DMA_IN_CONF0_CH2); + break; + + case A_DMA_OUT_CONF0_CH2 ... A_DMA_OUT_PERI_SEL_CH2: + r = read_addr_word((uint32_t*) &s->ch_conf[2][ESP32C3_GDMA_OUT_IDX], addr - A_DMA_OUT_CONF0_CH2); + break; + + default: +#if GDMA_WARNING + warn_report("[GDMA] Unsupported read to %08lx", addr); +#endif + break; + } + +#if GDMA_DEBUG + info_report("[GDMA] Reading from %08lx (%08lx)", addr, r); +#endif + + return r; +} + + +/** + * @brief Check whether the new status of any interrupt should trigger an interrupt + * + * @param s GDMA state structure + * @param chan Channel that has just been updated + */ +static void esp32c3_gdma_check_interrupt_status(ESP32C3GdmaState *s, uint32_t chan) +{ + DmaIntState* const int_st = &s->ch_int[chan]; + const uint32_t former = int_st->st; + + /* Calculate the new status and check for any difference */ + int_st->st = int_st->raw & int_st->ena; + + if (former != int_st->st) { + /* If all the status bits became low, lower the IRQ pin, else, raise it */ + qemu_set_irq(s->irq[chan], int_st->st ? 1 : 0); + } +} + + +/** + * @brief Set the status bit for the given channel. If the status triggers an interrupt, the corresponding + * IRQ will be set. +*/ +static void esp32c3_gdma_set_status(ESP32C3GdmaState *s, uint32_t chan, uint32_t mask) +{ + s->ch_int[chan].raw |= mask; + esp32c3_gdma_check_interrupt_status(s, chan); +} + + + +/** + * @brief Clear the status bit for the given channel +*/ +static void esp32c3_gdma_clear_status(ESP32C3GdmaState *s, uint32_t chan, uint32_t mask) +{ + s->ch_int[chan].raw &= ~mask; + esp32c3_gdma_check_interrupt_status(s, chan); +} + + +/** + * @brief Function called when a write to a channel interrupt register is performed + * + * @param s GDMA state structure + * @param chan Index of the channel to be written + * @param reg Offset, in bytes, of the register to modify + * @param value New value for the register + */ +static void esp32c3_gdma_write_int_state(ESP32C3GdmaState *s, uint32_t chan, uint32_t reg, uint32_t value) +{ + switch (reg) { + case offsetof(DmaIntState, ena): + s->ch_int[chan].ena = value; + break; + + case offsetof(DmaIntState, raw): + case offsetof(DmaIntState, clr): + /* Clear the bits that are set to 1, keep the remaining to their original value */ + s->ch_int[chan].raw &= ~value; + break; + + case offsetof(DmaIntState, st): + default: + /* Nothing to do, read-only register, return directly */ + return; + } + + /* Update the status and check if any interrupt needs to occur */ + esp32c3_gdma_check_interrupt_status(s, chan); +} + + +/** + * @brief Function called when a reset FIFO is requested + * + * @param s GDMA state structure + * @param chan Index of the channel + * @param in_out Index of the direction, ESP32C3_GDMA_IN_IDX or ESP32C3_GDMA_OUT_IDX, + * that needs a FIFO reset + */ +static void esp32c3_gdma_reset_fifo(ESP32C3GdmaState *s, uint32_t chan, uint32_t in_out) +{ +#if GDMA_DEBUG + info_report("Resetting FIFO for chan %d, direction: %d", chan, in_out); +#endif + /* Set the FIFO empty bit to 1, full bit to 0, and number of bytes of data to 0 */ + s->ch_conf[chan][in_out].status = R_DMA_INFIFO_STATUS_CH0_INFIFO_EMPTY_CH0_MASK; +} + + +/** + * @brief Read a descriptor from the guest machine + * + * @param s GDMA state structure + * @param addr Guest machine address + * + * @returns true if the transfer was a success, false else + */ +static bool esp32c3_gdma_read_descr(ESP32C3GdmaState *s, uint32_t addr, GdmaLinkedList* out) +{ + MemTxResult res = dma_memory_read(&s->dma_as, addr, out, sizeof(GdmaLinkedList), MEMTXATTRS_UNSPECIFIED); + return res == MEMTX_OK; +} + +/** + * @brief Write a descriptor to the guest machine + * + * @param s GDMA state structure + * @param addr Guest machine address + * + * @returns true if the transfer was a success, false else + */ +static bool esp32c3_gdma_write_descr(ESP32C3GdmaState *s, uint32_t addr, GdmaLinkedList* in) +{ + MemTxResult res = dma_memory_write(&s->dma_as, addr, in, sizeof(GdmaLinkedList), MEMTXATTRS_UNSPECIFIED); + return res == MEMTX_OK; +} + + + +/** + * @brief Read and write arbitrary data from and to the guest machine + * + * @param s GDMA state structure + * @param addr Guest machine address + * + * @returns true if the transfer was a success, false else + */ +static bool esp32c3_gdma_read_guest(ESP32C3GdmaState *s, uint32_t addr, void* data, uint32_t len) +{ + MemTxResult res = dma_memory_read(&s->dma_as, addr, data, len, MEMTXATTRS_UNSPECIFIED); + return res == MEMTX_OK; +} + +static bool esp32c3_gdma_write_guest(ESP32C3GdmaState *s, uint32_t addr, void* data, uint32_t len) +{ + MemTxResult res = dma_memory_write(&s->dma_as, addr, data, len, MEMTXATTRS_UNSPECIFIED); + return res == MEMTX_OK; +} + + +/** + * @brief Push current node (guest) address in the list of descriptors registers + * + * @param s GDMA state structure + * @param chan Channel to update + * @param chan Direction to update + * @param current New node (guest) address to set as the current + */ +static void esp32c3_gdma_push_descriptor(ESP32C3GdmaState *s, uint32_t chan, uint32_t dir, uint32_t current) +{ + GdmaLinkedList next_node; + uint32_t next = 0; + DmaConfigState* state = &s->ch_conf[chan][dir]; + + /* Assign the current descriptor address to the state register */ + state->state = current & R_DMA_OUT_STATE_CH0_OUTLINK_DSCR_ADDR_CH0_MASK; + + /* On real hardware, if the former address is incorrect, the current address is copied to this + * register. */ + state->bfr_bfr_desc_addr = state->bfr_desc_addr; + /* On real hardware, state->bfr_desc_addr is taken from state->desc_addr, even is `current` is valid */ + state->bfr_desc_addr = state->desc_addr; + + /* Get the next address out of the guest RAM */ + const bool valid = esp32c3_gdma_read_descr(s, current, &next_node); + if (valid) { + next = next_node.next_addr; + } + state->desc_addr = next; +} + + + +/** + * @brief Jump to the next node list and assign it to the given node + * + * @param s GDMA state structure + * @param node Node to get the next neighbor of + * + * @returns true if the next node is valid, false else + */ +static inline bool esp32c3_gdma_next_list_node(ESP32C3GdmaState *s, uint32_t chan, uint32_t dir, GdmaLinkedList* node) +{ + const uint32_t current = node->next_addr; + esp32c3_gdma_push_descriptor(s, chan, dir, current); + return esp32c3_gdma_read_descr(s, current, node); +} + + +/** + * @brief Get the first descriptor to process when a restart is requested. + * We need to get the "next" node of the last one processed, which is in `desc_addr` register + * + * @param s GDMA state structure + * @param chan Channel to restart + * @param dir Direction (INT or OUT) to restart + * @param out Filled with the output guest address + */ +static void esp32c3_gdma_get_restart_buffer(ESP32C3GdmaState *s, uint32_t chan, uint32_t dir, uint32_t* out) +{ + DmaConfigState* state = &s->ch_conf[chan][dir]; + // GdmaLinkedList* list = NULL; + /* The next node to use is taken from state->state's lowest 18 bit. Append it to the DRAM address */ + const uint32_t dram_upper_bits = ESP32C3_GDMA_RAM_ADDR & (~R_DMA_OUT_STATE_CH0_OUTLINK_DSCR_ADDR_CH0_MASK); + const uint32_t guest_addr = dram_upper_bits | FIELD_EX32(state->state, DMA_OUT_STATE_CH0, OUTLINK_DSCR_ADDR_CH0); + + *out = guest_addr; +} + + +/** + * Check the header file for more info about this function + */ +bool esp32c3_gdma_get_channel_periph(ESP32C3GdmaState *s, GdmaPeripheral periph, int dir, uint32_t* chan) +{ + /* If the state, the peripheral or the direction is invalid, return directly */ + if (s == NULL || chan == NULL || + periph > GDMA_LAST || periph == GDMA_RSVD1 || periph == GDMA_RSVD4 || periph == GDMA_RSVD5 || + dir < 0 || dir >= ESP32C3_GDMA_CONF_COUNT) + { + return false; + } + + /* Check all the channels of the GDMA */ + for (int i = 0; i < ESP32C3_GDMA_CHANNEL_COUNT; i++) { + /* IN/OUT PERI registers have the same organization, can use any macro. + * Look for the channel that was configured with the given peripheral. It must be marked as "started" too */ + if ( FIELD_EX32(s->ch_conf[i][dir].peripheral, DMA_IN_PERI_SEL_CH0, PERI_IN_SEL_CH0) == periph || + FIELD_EX32(s->ch_conf[i][dir].link, DMA_OUT_LINK_CH0, OUTLINK_START_CH0)) { + + *chan = i; + return true; + } + } + + return false; +} + + +/** + * @brief Read data from guest RAM pointed by the linked list configured in the given DmaConfigState index. + * `size` bytes will be read and stored in `buffer`. + */ +bool esp32c3_gdma_read_channel(ESP32C3GdmaState *s, uint32_t chan, uint8_t* buffer, uint32_t size) +{ + DmaConfigState* state = &s->ch_conf[chan][ESP32C3_GDMA_OUT_IDX]; + + state->link &= R_DMA_OUT_LINK_CH0_OUTLINK_ADDR_CH0_MASK; + + /* Same goes for the status */ + esp32c3_gdma_clear_status(s, chan, R_DMA_INT_RAW_CH0_OUT_DONE_CH0_INT_RAW_MASK | + R_DMA_INT_RAW_CH0_OUT_EOF_CH0_INT_RAW_MASK); + + /* Get the guest DRAM address */ + uint32_t out_addr = ((ESP32C3_GDMA_RAM_ADDR >> 20) << 20) | FIELD_EX32(state->link, DMA_OUT_LINK_CH0, OUTLINK_ADDR_CH0); + + /* Boolean to mark whether we need to check the owner for in and out buffers */ + const bool owner_check_out = FIELD_EX32(state[ESP32C3_GDMA_OUT_IDX].conf1, DMA_OUT_CONF1_CH0, OUT_CHECK_OWNER_CH0); + + /* Boolean to mark whether the transmit (out) buffers must have their owner bit cleared here */ + const bool clear_out = FIELD_EX32(state[ESP32C3_GDMA_OUT_IDX].conf0, DMA_OUT_CONF0_CH0, OUT_AUTO_WRBACK_CH0); + + /* Pointer to the lists that will be browsed by the loop below */ + GdmaLinkedList out_list; + + /* Boolean to mark whether a descriptor error occurred during the transfer */ + bool valid = true; + + /* Set the current buffer (guest address) in the `desc_addr` register */ + valid = esp32c3_gdma_read_descr(s, out_addr, &out_list); + esp32c3_gdma_push_descriptor(s, chan, ESP32C3_GDMA_OUT_IDX, out_addr); + + /* Check that the address is valid. If the owner must be checked, make sure owner is the DMA controller. + * On the real hardware, both in and out are checked at the same time, so in case of an error, both bits + * are set. Replicate the same behavior here. */ + if ( !valid || (owner_check_out && !out_list.config.owner) ) { + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_OUT_DSCR_ERR_CH0_INT_RAW_MASK); + return false; + } + + /* Store the current number of bytes written to `buffer` parameter */ + uint32_t consumed = 0; + bool exit_loop = false; + bool error = false; + + while (!exit_loop && !error) { + /* Calculate the number of bytes to read from the OUT channel */ + const uint32_t remaining = size - consumed; + const uint32_t min = MIN(out_list.config.length, remaining); + + valid = esp32c3_gdma_read_guest(s, out_list.buf_addr, buffer + consumed, min); + if (!valid) { + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_OUT_DSCR_ERR_CH0_INT_RAW_MASK); + error = true; + break; + } + consumed += min; + + if (consumed == size) { + exit_loop = true; + } + + /* If we reached the end of the TX descriptor, we can jump to the next buffer */ + if (min == out_list.config.length) { + + /* Before jumping to the next node, clear the owner bit if needed */ + if (clear_out) { + out_list.config.owner = 0; + + /* Write back the modified descriptor, should always be valid */ + valid = esp32c3_gdma_read_descr(s, out_addr, &out_list); + assert(valid); + } + + const bool eof_bit = out_list.config.suc_eof; + + /* Retrieve the next node while updating the virtual guest address */ + out_addr = out_list.next_addr; + valid = esp32c3_gdma_next_list_node(s, chan, ESP32C3_GDMA_OUT_IDX, &out_list); + + /* Only check the valid flag and the owner if we don't have to exit the loop*/ + if ( !exit_loop && (!valid || (owner_check_out && !out_list.config.owner)) ) { + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_OUT_DSCR_ERR_CH0_INT_RAW_MASK); + error = true; + } + + /* If the EOF bit was set, the real controller doesn't stop the transfer, it simply + * sets the status accordingly (and generates an interrupt if enabled) */ + if (eof_bit) { + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_OUT_EOF_CH0_INT_RAW_MASK | + R_DMA_INT_RAW_CH0_OUT_TOTAL_EOF_CH0_INT_RAW_MASK); + } + } + } + + /* Check if all the bytes were sent successfully */ + if (exit_loop && consumed != size) { + /* TODO: which error should be triggered ?*/ + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_OUT_DSCR_ERR_CH0_INT_RAW_MASK); + error = true; + } + + if (!error) { + /* Set the transfer as completed. EOF should have already been triggered within the loop */ + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_OUT_DONE_CH0_INT_RAW_MASK); + } + + return !error; +} + + +/** + * @brief Write data to the guest RAM pointed by the linked list configured in the given DmaConfigState index. + * `size` bytes from `buffer` will be written to guest machine's RAM. + */ +bool esp32c3_gdma_write_channel(ESP32C3GdmaState *s, uint32_t chan, uint8_t* buffer, uint32_t size) +{ + DmaConfigState* state = &s->ch_conf[chan][ESP32C3_GDMA_IN_IDX]; + + /* Clear the (RE)START fields, i.e., only keep the link address */ + state->link &= R_DMA_OUT_LINK_CH0_OUTLINK_ADDR_CH0_MASK; + + /* Same goes for the status */ + esp32c3_gdma_clear_status(s, chan, R_DMA_INT_RAW_CH0_IN_DONE_CH0_INT_RAW_MASK | + R_DMA_INT_RAW_CH0_IN_SUC_EOF_CH0_INT_RAW_MASK); + + /* Get highest 12 bits of the DRAM address */ + uint32_t in_addr = ((ESP32C3_GDMA_RAM_ADDR >> 20) << 20) | FIELD_EX32(state->link, DMA_IN_LINK_CH0, INLINK_ADDR_CH0); + + /* Boolean to mark whether we need to check the owner for in buffers */ + const bool owner_check_in = FIELD_EX32(state->conf1, DMA_IN_CONF1_CH0, IN_CHECK_OWNER_CH0); + + /* Pointer to the lists that will be browsed by the loop below */ + GdmaLinkedList in_list = { 0 }; + /* Boolean to mark whether a descriptor error occurred during the transfer */ + bool valid = true; + + valid = esp32c3_gdma_read_descr(s, in_addr, &in_list); + esp32c3_gdma_push_descriptor(s, chan, ESP32C3_GDMA_IN_IDX, in_addr); + + if ( !valid || (owner_check_in && !in_list.config.owner) ) { + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_IN_DSCR_ERR_CH0_INT_RAW_MASK); + return false; + } + + /* Clear the number of bytes written to the "in" buffer and the owner */ + in_list.config.length = 0; + + uint32_t consumed = 0; + bool exit_loop = false; + bool error = false; + + while (!exit_loop && !error) { + + /* Calculate the number of bytes to write to the in channel */ + const uint32_t remaining = size - consumed; + const uint32_t min = MIN(in_list.config.size, remaining); + + /* Perform the actual copy, the in buffer address will always be at the beginning because the data + * to write to it are contiguous (`buffer` parameter) */ + valid = esp32c3_gdma_write_guest(s, in_list.buf_addr, buffer + consumed, min); + if (!valid) { + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_IN_DSCR_ERR_CH0_INT_RAW_MASK); + error = true; + } + + /* Update the number of bytes written to the "in" buffer */ + in_list.config.length += min; + consumed += min; + + if (size == consumed) { + exit_loop = true; + } + + /* If we reached the end of the "node", go to the next one */ + if (in_list.config.size == in_list.config.length) { + /* Clear the owner bit, set the length to the maximum bytes readable */ + in_list.config.owner = 0; + + /* During peripheral-to-memory transfers, the eof bit is only used to set a status bit, and generate + * an interrupt if enabled. If we still have bytes to send, we won't stop the transfer. + * In all cases, reset this bit as it must be only set at the end of the buffer. */ + if (in_list.config.suc_eof) { + in_list.config.suc_eof = 0; + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_IN_SUC_EOF_CH0_INT_RAW_MASK); + } + + /* Write back the IN node to guest RAM */ + valid = esp32c3_gdma_write_descr(s, in_addr, &in_list); + assert(valid); + + /* Get the next virtual address before replacing the current list node content */ + const uint32_t next_addr = in_list.next_addr; + + /* Even if we have to exit the loop, we still have to push the next address to the descriptors stack */ + if (exit_loop) { + esp32c3_gdma_push_descriptor(s, chan, ESP32C3_GDMA_IN_IDX, next_addr); + break; + } + + /* In the case where the transfer is finished, we should still fetch the next node, + * but we should not override the current in_list variable as it is used outside the loop + * to reset the owner and update the suc_eof flag */ + valid = esp32c3_gdma_next_list_node(s, chan, ESP32C3_GDMA_IN_IDX, &in_list); + + if (!valid || (owner_check_in && !in_list.config.owner)) { + /* Check the validity of the next node if we have to continue the loop (transfer finished) */ + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_IN_DSCR_ERR_CH0_INT_RAW_MASK); + error = true; + } else { + /* Continue the loop normally, next RX descriptor set to current */ + in_list.config.length = 0; + + /* Update the current in guest address */ + in_addr = next_addr; + } + } + } + + if (!error) { + /* In all cases (error or not), let's set the End-of-list in the receiver */ + in_list.config.suc_eof = 1; + in_list.config.owner = 0; + + valid = esp32c3_gdma_write_descr(s, in_addr, &in_list); + assert(valid); + + /* And store the EOF RX descriptor GUEST address in the correct register. + * This can be used in the ISR to know which buffer has just been processed. */ + state->suc_eof_desc_addr = in_addr; + + /* Set the transfer as completed for both the IN and OUT link */ + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_IN_DONE_CH0_INT_RAW_MASK); + } + + return !error; +} + + +/** + * @brief Check if a memory-to-memory transfer can be started and start it if possible + * + * @param s GDMA state structure + * @param chan Index of the channel + */ +static void esp32c3_gdma_check_and_start_mem_transfer(ESP32C3GdmaState *s, uint32_t chan) +{ + DmaConfigState* state = s->ch_conf[chan]; + /* Keep the distinction between start and restart because it influences the first descriptor to process */ + const bool in_start = FIELD_EX32(state[ESP32C3_GDMA_IN_IDX].link, DMA_IN_LINK_CH0, INLINK_START_CH0) ? true : false; + const bool in_restart = FIELD_EX32(state[ESP32C3_GDMA_IN_IDX].link, DMA_IN_LINK_CH0, INLINK_RESTART_CH0) ? true : false; + const bool out_start = FIELD_EX32(state[ESP32C3_GDMA_OUT_IDX].link, DMA_OUT_LINK_CH0, OUTLINK_START_CH0) ? true : false; + const bool out_restart = FIELD_EX32(state[ESP32C3_GDMA_OUT_IDX].link, DMA_OUT_LINK_CH0, OUTLINK_RESTART_CH0) ? true : false; + + /* A memory-to-memory transfer can be started if MEM_TRANS is enabled, OUTLINK_(RE)START is set + * and INLINK_(RE)START is set */ + if (FIELD_EX32(state[ESP32C3_GDMA_IN_IDX].conf0, DMA_IN_CONF0_CH0, MEM_TRANS_EN_CH0) + && (in_start || in_restart) + && (out_start || out_restart)) + { + /* Clear the (RE)START fields, i.e., only keep the link address */ + state[ESP32C3_GDMA_OUT_IDX].link &= R_DMA_OUT_LINK_CH0_OUTLINK_ADDR_CH0_MASK; + state[ESP32C3_GDMA_IN_IDX].link &= R_DMA_IN_LINK_CH0_INLINK_ADDR_CH0_MASK; + /* Same goes for the status */ + esp32c3_gdma_clear_status(s, chan, R_DMA_INT_RAW_CH0_IN_DONE_CH0_INT_RAW_MASK | + R_DMA_INT_RAW_CH0_OUT_DONE_CH0_INT_RAW_MASK | + R_DMA_INT_RAW_CH0_OUT_EOF_CH0_INT_RAW_MASK | + R_DMA_INT_RAW_CH0_IN_SUC_EOF_CH0_INT_RAW_MASK); + + /* Get highest 12 bits of the DRAM address */ + const uint32_t high = (ESP32C3_GDMA_RAM_ADDR >> 20) << 20; + + /* TODO: in an inlink, when burst mode is enabled, size and buffer address must be word-aligned. */ + /* If a start was performed, the first descriptor address to process is in DMA_OUT_LINK_CHn register, + * if a restart was performed, the first buffer is the `next` node of `desc_addr` register */ + uint32_t out_addr = high; + uint32_t in_addr = high; + + if (out_start) { + out_addr |= FIELD_EX32(state[ESP32C3_GDMA_OUT_IDX].link, DMA_OUT_LINK_CH0, OUTLINK_ADDR_CH0); + } else { + esp32c3_gdma_get_restart_buffer(s, chan, ESP32C3_GDMA_OUT_IDX, &out_addr); + } + + if (in_start) { + in_addr |= FIELD_EX32(state[ESP32C3_GDMA_IN_IDX].link, DMA_IN_LINK_CH0, INLINK_ADDR_CH0); + } else { + esp32c3_gdma_get_restart_buffer(s, chan, ESP32C3_GDMA_IN_IDX, &in_addr); + } + + /* Boolean to mark whether we need to check the owner for in and out buffers */ + const bool owner_check_out = FIELD_EX32(state[ESP32C3_GDMA_OUT_IDX].conf1, DMA_OUT_CONF1_CH0, OUT_CHECK_OWNER_CH0); + const bool owner_check_in = FIELD_EX32(state[ESP32C3_GDMA_IN_IDX].conf1, DMA_IN_CONF1_CH0, IN_CHECK_OWNER_CH0); + /* Boolean to mark whether the transmit (out) buffers must have their owner bit cleared here */ + const bool clear_out = FIELD_EX32(state[ESP32C3_GDMA_OUT_IDX].conf0, DMA_OUT_CONF0_CH0, OUT_AUTO_WRBACK_CH0); + + /* Pointer to the lists that will be browsed by the loop below */ + GdmaLinkedList out_list = { 0 }; + GdmaLinkedList in_list = { 0 }; + /* Boolean to mark whether a descriptor error occurred during the transfer */ + bool valid = true; + bool error = false; + + /* Get the content of the descriptor located at guest address out_addr */ + valid = esp32c3_gdma_read_descr(s, out_addr, &out_list); + esp32c3_gdma_push_descriptor(s, chan, ESP32C3_GDMA_OUT_IDX, out_addr); + + /* Check that the address is valid. If the owner must be checked, make sure owner is the DMA controller. + * On the real hardware, both in and out are checked at the same time, so in case of an error, both bits + * are set. Replicate the same behavior here. */ + if ( !valid || (owner_check_out && !out_list.config.owner) ) { + /* In case of an error, go directly to the next node (as the C3 hardware does) */ + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_OUT_DSCR_ERR_CH0_INT_RAW_MASK); + error = true; + } + + valid = esp32c3_gdma_read_descr(s, in_addr, &in_list); + esp32c3_gdma_push_descriptor(s, chan, ESP32C3_GDMA_IN_IDX, in_addr); + + if ( !valid || (owner_check_in && !in_list.config.owner) ) { + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_IN_DSCR_ERR_CH0_INT_RAW_MASK); + error = true; + } + + /* If any of the error bit has been set, return directly */ + if (error) { + return; + } + + /* We can keep track of the total amount of bytes written in order to simulate a more or less + * accurate timing (and an interrupt) */ + int total = 0; + + /* Clear the number of bytes written to the "in" buffer and the owner */ + in_list.config.length = 0; + + /* Number of bytes remaining in the current "out" buffer */ + uint32_t remaining = out_list.config.length; + /* Store the current number of bytes consumed in the "out" buffer */ + uint32_t consumed = 0; + + bool exit_loop = false; + + /* Allocate a temporary buffer big enough to store any descriptor data */ + void* tmp_buffer = g_malloc(4096 * sizeof(uint8_t)); + if (tmp_buffer == NULL) { + error_report("[GDMA] No more memory in host\n"); + return; + } + + while (!exit_loop && !error) { + + /* Calculate the number of bytes to send to the in channel */ + const uint32_t min = MIN(in_list.config.size, out_list.config.length); + + /* Perform the actual copy, for the same reasons as stated above, use the error boolean */ + valid = esp32c3_gdma_read_guest(s, out_list.buf_addr + consumed, tmp_buffer, min); + if (!valid) { + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_OUT_DSCR_ERR_CH0_INT_RAW_MASK); + error = true; + } + valid = esp32c3_gdma_write_guest(s, in_list.buf_addr + in_list.config.length, tmp_buffer, min); + if (!valid) { + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_IN_DSCR_ERR_CH0_INT_RAW_MASK); + error = true; + } + + /* Update the number of bytes written to the "in" buffer */ + in_list.config.length += min; + consumed += min; + total += min; + + /* Even if we reached the end of the TX descriptor, we still have to update RX descriptors + * and registers, use `exit_loop` instead of break or return */ + /* If we don't have any more bytes in the "out" buffer, we can skip to the next buffer */ + if (remaining == consumed) { + /* Before jumping to the next node, clear the owner bit */ + if (clear_out) { + out_list.config.owner = 0; + /* Write back the modified descriptor, should always be valid */ + valid = esp32c3_gdma_write_descr(s, out_addr, &out_list); + assert(valid); + } + exit_loop = out_list.config.suc_eof ? true : false; + + const uint32_t next_addr = out_list.next_addr; + valid = esp32c3_gdma_next_list_node(s, chan, ESP32C3_GDMA_OUT_IDX, &out_list); + + /* Only check the valid flag and the owner if we don't have to exit the loop*/ + if ( !exit_loop && (!valid || (owner_check_out && !out_list.config.owner)) ) { + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_OUT_DSCR_ERR_CH0_INT_RAW_MASK); + error = true; + } else { + /* Update "remaining" with the number of bytes to transfer from the new buffer */ + out_addr = next_addr; + remaining = out_list.config.length; + consumed = 0; + } + } + + + /* If we reached the end of the "node", go to the next one */ + if (in_list.config.size == in_list.config.length) { + + in_list.config.owner = 0; + + /* Write back the IN node to guest RAM */ + valid = esp32c3_gdma_write_descr(s, in_addr, &in_list); + assert(valid); + + /* Check that we do have more "in" buffers, if that's not the case, raise an error.. + * TODO: Check if the behavior is the same as Peripheral-to-Memory transfers, where + * this bit is only used to generate and interrupt. */ + if (!exit_loop && in_list.config.suc_eof) { + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_IN_DSCR_EMPTY_CH0_INT_RAW_MASK); + error = true; + break; + } + + const uint32_t next_addr = in_list.next_addr; + + /* In the case where the transfer is finished, we should still "push" the next node + * to our descriptors stack, but we should not modify the structure itself as we will + * reset the owner and update the suc_eof flag */ + if (exit_loop) { + esp32c3_gdma_push_descriptor(s, chan, ESP32C3_GDMA_IN_IDX, next_addr); + break; + } + + /* We have to continue the loop, so fetch the next node, it will also update the descriptors stack */ + valid = esp32c3_gdma_next_list_node(s, chan, ESP32C3_GDMA_IN_IDX, &in_list); + + /* Check the validity of the next node if we have to continue the loop (transfer finished) */ + if (!valid || (owner_check_in && !in_list.config.owner)) { + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_IN_DSCR_ERR_CH0_INT_RAW_MASK); + error = true; + } else { + /* Continue the loop normally, next RX descriptor set to current */ + in_list.config.length = 0; + + /* Update the current in guest address */ + in_addr = next_addr; + } + } + + } + + if (!error) { + /* In all cases (error or not), let's set the End-of-list in the receiver */ + in_list.config.suc_eof = 1; + in_list.config.owner = 0; + + /* Write back the previous changes */ + valid = esp32c3_gdma_write_descr(s, in_addr, &in_list); + assert(valid); + + /* And store the EOF RX descriptor GUEST address in the correct register. + * This can be used in the ISR to know which buffer has just been processed. */ + state[ESP32C3_GDMA_IN_IDX].suc_eof_desc_addr = in_addr; + + /* Set the transfer as completed for both the IN and OUT link */ + esp32c3_gdma_set_status(s, chan, R_DMA_INT_RAW_CH0_IN_DONE_CH0_INT_RAW_MASK | + R_DMA_INT_RAW_CH0_OUT_DONE_CH0_INT_RAW_MASK | + R_DMA_INT_RAW_CH0_OUT_EOF_CH0_INT_RAW_MASK | + R_DMA_INT_RAW_CH0_IN_SUC_EOF_CH0_INT_RAW_MASK); + } + + g_free(tmp_buffer); + } +} + + + +/** + * @brief Check whether the given register offset corresponds to a read-only register + * + * @param offset Offset of the register in DmaConfigState structure, in bytes + * + * @return true is the register is read-only, false else + */ +static bool esp32c3_gdma_register_read_only(uint32_t offset) +{ + return offset >= offsetof(DmaConfigState, state) && offset < offsetof(DmaConfigState, priority); +} + + +/** + * @brief Function called when a configuration register was written to + * + * @param s GDMA state structure + * @param chan Index of the channel to be written + * @param in_out Index of the sub-channel, which is ESP32C3_GDMA_IN_IDX or ESP32C3_GDMA_OUT_IDX + * @param addr_in_block Address in bytes of the register being written to in the block + * @param value 32-bit value being written to the register + */ +static void esp32c3_gdma_write_chan_conf(ESP32C3GdmaState *s, uint32_t chan, uint32_t in_out, + uint32_t addr_in_block, uint32_t value) +{ + DmaConfigState* state = &s->ch_conf[chan][in_out]; + uint32_t* const reg_addr = (uint32_t*) ((uint8_t*) state + addr_in_block); + + /* Dereference the former value of the register being written to */ + const uint32_t former = *reg_addr; + + /* Write the new value to the register if not read-only! */ + if (!esp32c3_gdma_register_read_only(addr_in_block)) { + *reg_addr = value; + } + + /* We will only support a subset of GDMA registers for now. To add support for more registers, + * the following snippet can be update */ + uint32_t start_mask = 0; + uint32_t restart_mask = 0; + switch(addr_in_block) { + + /* No matter the channel and in/out direction, the registers are organized the same way, + * so we can use the macros for any channel */ + case offsetof(DmaConfigState, conf0): + /* Check the reset bit, call the reset function on negative edge */ + if (FIELD_EX32(value, DMA_IN_CONF0_CH0, IN_RST_CH0) == 0 && + FIELD_EX32(former, DMA_IN_CONF0_CH0, IN_RST_CH0) != 0) + { + esp32c3_gdma_reset_fifo(s, chan, in_out); + } + /* Check if memory transfer has just been enabled (only valid for IN channels) */ + if (in_out == ESP32C3_GDMA_IN_IDX && + FIELD_EX32(value, DMA_IN_CONF0_CH0, MEM_TRANS_EN_CH0)) + { + esp32c3_gdma_check_and_start_mem_transfer(s, chan); + } + break; + + case offsetof(DmaConfigState, link): + /* For IN and OUT, the START bit is not at the same offset, so we need to test both separately */ + start_mask = ESP32C3_GDMA_IN_IDX ? R_DMA_IN_LINK_CH0_INLINK_START_CH0_MASK : R_DMA_OUT_LINK_CH0_OUTLINK_START_CH0_MASK; + restart_mask = ESP32C3_GDMA_IN_IDX ? R_DMA_IN_LINK_CH0_INLINK_RESTART_CH0_MASK : R_DMA_OUT_LINK_CH0_OUTLINK_RESTART_CH0_MASK; + + /* Check if any of the previous two bits has just been enabled */ + if ((value & start_mask) || (value & restart_mask)) + { + esp32c3_gdma_check_and_start_mem_transfer(s, chan); + } + + default: + break; + } +} + + +static void esp32c3_gdma_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + ESP32C3GdmaState *s = ESP32C3_GDMA(opaque); + +#if GDMA_DEBUG + info_report("[GDMA] Writing to %08lx (%08lx)", addr, value); +#endif + + switch(addr) { + case A_DMA_INT_RAW_CH0 ... A_DMA_INT_CLR_CH2: + esp32c3_gdma_write_int_state(s, + addr / ESP32C3_GDMA_INT_REGS_SIZE, + addr % ESP32C3_GDMA_INT_REGS_SIZE, + value); + break; + + case A_DMA_MISC_CONF: + s->misc_conf = value; + break; + + case A_DMA_IN_CONF0_CH0 ... A_DMA_IN_PERI_SEL_CH0: + esp32c3_gdma_write_chan_conf(s, 0, ESP32C3_GDMA_IN_IDX, addr - A_DMA_IN_CONF0_CH0, value); + break; + + case A_DMA_OUT_CONF0_CH0 ... A_DMA_OUT_PERI_SEL_CH0: + esp32c3_gdma_write_chan_conf(s, 0, ESP32C3_GDMA_OUT_IDX, addr - A_DMA_OUT_CONF0_CH0, value); + break; + + case A_DMA_IN_CONF0_CH1 ... A_DMA_IN_PERI_SEL_CH1: + esp32c3_gdma_write_chan_conf(s, 1, ESP32C3_GDMA_IN_IDX, addr - A_DMA_IN_CONF0_CH1, value); + break; + + case A_DMA_OUT_CONF0_CH1 ... A_DMA_OUT_PERI_SEL_CH1: + esp32c3_gdma_write_chan_conf(s, 1, ESP32C3_GDMA_OUT_IDX, addr - A_DMA_OUT_CONF0_CH1, value); + break; + + case A_DMA_IN_CONF0_CH2 ... A_DMA_IN_PERI_SEL_CH2: + esp32c3_gdma_write_chan_conf(s, 2, ESP32C3_GDMA_IN_IDX, addr - A_DMA_IN_CONF0_CH2, value); + break; + + case A_DMA_OUT_CONF0_CH2 ... A_DMA_OUT_PERI_SEL_CH2: + esp32c3_gdma_write_chan_conf(s, 2, ESP32C3_GDMA_OUT_IDX, addr - A_DMA_OUT_CONF0_CH2, value); + break; + + default: +#if GDMA_WARNING + warn_report("[GDMA] Unsupported write to %08lx (%08lx)", addr, value); +#endif + break; + } + +} + +static const MemoryRegionOps esp32c3_gdma_ops = { + .read = esp32c3_gdma_read, + .write = esp32c3_gdma_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + + +static Property esp32c3_gdma_properties[] = { + DEFINE_PROP_LINK("soc_mr", ESP32C3GdmaState, soc_mr, TYPE_MEMORY_REGION, MemoryRegion*), + DEFINE_PROP_END_OF_LIST(), +}; + + +static void esp32c3_gdma_reset(DeviceState *dev) +{ + ESP32C3GdmaState *s = ESP32C3_GDMA(dev); + memset(s->ch_int, 0, sizeof(s->ch_int)); + memset(s->ch_conf, 0, sizeof(s->ch_conf)); + s->misc_conf = 0; + + /* Set the FIFOs as empty */ + for (int i = 0; i < ESP32C3_GDMA_CHANNEL_COUNT; i++) { + qemu_irq_lower(s->irq[i]); + + for (int j = 0; j < ESP32C3_GDMA_CONF_COUNT; j++) { + esp32c3_gdma_reset_fifo(s, i, j); + } + } + +} + + +static void esp32c3_gdma_realize(DeviceState *dev, Error **errp) +{ + ESP32C3GdmaState *s = ESP32C3_GDMA(dev); + + /* Make sure the DRAM MemoryRegion was set */ + assert(s->soc_mr != NULL); + + address_space_init(&s->dma_as, s->soc_mr, "esp32c3.gdma"); +} + + +static void esp32c3_gdma_init(Object *obj) +{ + ESP32C3GdmaState *s = ESP32C3_GDMA(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32c3_gdma_ops, s, + TYPE_ESP32C3_GDMA, ESP32C3_GDMA_REGS_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + + for (int i = 0; i < ESP32C3_GDMA_CHANNEL_COUNT; i++) { + sysbus_init_irq(sbd, &s->irq[i]); + } + + esp32c3_gdma_reset((DeviceState*) s); +} + + +static void esp32c3_gdma_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32c3_gdma_reset; + dc->realize = esp32c3_gdma_realize; + device_class_set_props(dc, esp32c3_gdma_properties); +} + +static const TypeInfo esp32c3_gdma_info = { + .name = TYPE_ESP32C3_GDMA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32C3GdmaState), + .instance_init = esp32c3_gdma_init, + .class_init = esp32c3_gdma_class_init +}; + +static void esp32c3_gdma_register_types(void) +{ + type_register_static(&esp32c3_gdma_info); +} + +type_init(esp32c3_gdma_register_types) diff --git a/hw/dma/meson.build b/hw/dma/meson.build index f3f0661bc3c3..925f3cc2bdc5 100644 --- a/hw/dma/meson.build +++ b/hw/dma/meson.build @@ -14,3 +14,4 @@ softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_dma.c')) softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_dma.c')) softmmu_ss.add(when: 'CONFIG_SIFIVE_PDMA', if_true: files('sifive_pdma.c')) softmmu_ss.add(when: 'CONFIG_XLNX_CSU_DMA', if_true: files('xlnx_csu_dma.c')) +softmmu_ss.add(when: 'CONFIG_RISCV_ESP32C3', if_true: files('esp32c3_gdma.c')) diff --git a/hw/gpio/esp32_gpio.c b/hw/gpio/esp32_gpio.c new file mode 100644 index 000000000000..84aefd4ce06a --- /dev/null +++ b/hw/gpio/esp32_gpio.c @@ -0,0 +1,102 @@ +/* + * ESP32 GPIO emulation + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/gpio/esp32_gpio.h" + + + +static uint64_t esp32_gpio_read(void *opaque, hwaddr addr, unsigned int size) +{ + Esp32GpioState *s = ESP32_GPIO(opaque); + uint64_t r = 0; + switch (addr) { + case A_GPIO_STRAP: + r = s->strap_mode; + break; + + default: + break; + } + return r; +} + +static void esp32_gpio_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ +} + +static const MemoryRegionOps uart_ops = { + .read = esp32_gpio_read, + .write = esp32_gpio_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_gpio_reset(DeviceState *dev) +{ +} + +static void esp32_gpio_realize(DeviceState *dev, Error **errp) +{ +} + +static void esp32_gpio_init(Object *obj) +{ + Esp32GpioState *s = ESP32_GPIO(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + /* Set the default value for the strap_mode property */ + object_property_set_int(obj, "strap_mode", ESP32_STRAP_MODE_FLASH_BOOT, &error_fatal); + + memory_region_init_io(&s->iomem, obj, &uart_ops, s, + TYPE_ESP32_GPIO, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); +} + +static Property esp32_gpio_properties[] = { + /* The strap_mode needs to be explicitly set in the instance init, thus, set + * the default value to 0. */ + DEFINE_PROP_UINT32("strap_mode", Esp32GpioState, strap_mode, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32_gpio_reset; + dc->realize = esp32_gpio_realize; + device_class_set_props(dc, esp32_gpio_properties); +} + +static const TypeInfo esp32_gpio_info = { + .name = TYPE_ESP32_GPIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32GpioState), + .instance_init = esp32_gpio_init, + .class_init = esp32_gpio_class_init, + .class_size = sizeof(Esp32GpioClass), +}; + +static void esp32_gpio_register_types(void) +{ + type_register_static(&esp32_gpio_info); +} + +type_init(esp32_gpio_register_types) diff --git a/hw/gpio/esp32c3_gpio.c b/hw/gpio/esp32c3_gpio.c new file mode 100644 index 000000000000..1e842381f212 --- /dev/null +++ b/hw/gpio/esp32c3_gpio.c @@ -0,0 +1,49 @@ +/* + * ESP32-C3 GPIO emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/gpio/esp32c3_gpio.h" + + +static void esp32c3_gpio_init(Object *obj) +{ + /* Set the default value for the property */ + object_property_set_int(obj, "strap_mode", ESP32C3_STRAP_MODE_FLASH_BOOT, &error_fatal); +} + +/* If we need to override any function from the parent (reset, realize, ...), it shall be done + * in this class_init function */ +static void esp32c3_gpio_class_init(ObjectClass *klass, void *data) +{ +} + +static const TypeInfo esp32c3_gpio_info = { + .name = TYPE_ESP32C3_GPIO, + .parent = TYPE_ESP32_GPIO, + .instance_size = sizeof(ESP32C3GPIOState), + .instance_init = esp32c3_gpio_init, + .class_init = esp32c3_gpio_class_init, + .class_size = sizeof(ESP32C3GPIOClass), +}; + +static void esp32c3_gpio_register_types(void) +{ + type_register_static(&esp32c3_gpio_info); +} + +type_init(esp32c3_gpio_register_types) diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build index b726e6d27a41..25aef3f82f2f 100644 --- a/hw/gpio/meson.build +++ b/hw/gpio/meson.build @@ -12,3 +12,5 @@ softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gpio.c')) softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_gpio.c')) softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_gpio.c')) softmmu_ss.add(when: 'CONFIG_SIFIVE_GPIO', if_true: files('sifive_gpio.c')) +softmmu_ss.add(when: 'CONFIG_XTENSA_ESP32', if_true: files('esp32_gpio.c')) +softmmu_ss.add(when: 'CONFIG_RISCV_ESP32C3', if_true: files('esp32_gpio.c', 'esp32c3_gpio.c')) diff --git a/hw/i2c/esp32_i2c.c b/hw/i2c/esp32_i2c.c new file mode 100644 index 000000000000..1d36b8ad5704 --- /dev/null +++ b/hw/i2c/esp32_i2c.c @@ -0,0 +1,283 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/error-report.h" +#include "hw/i2c/esp32_i2c.h" +#include "hw/irq.h" + +static void esp32_i2c_do_transaction(Esp32I2CState * s); +static void esp32_i2c_update_irq(Esp32I2CState * s); + +static void esp32_i2c_reset(DeviceState * dev) +{ + Esp32I2CState * s = Esp32_I2C(dev); + + fifo8_reset(&s->rx_fifo); + fifo8_reset(&s->tx_fifo); + s->trans_ongoing = false; + s->ctr_reg = 0; + s->timeout_reg = 0; + s->int_ena_reg = 0; + s->int_raw_reg = 0; + s->sda_hold_reg = 0; + s->sda_sample_reg = 0; + s->high_period_reg = 0; + s->low_period_reg = 0; + s->start_hold_reg = 0; + s->rstart_setup_reg = 0; + s->stop_hold_reg = 0; + s->stop_setup_reg = 0; + memset(s->cmd_reg, 0, sizeof(s->cmd_reg)); + + fifo8_reset(&s->tx_fifo); + fifo8_reset(&s->rx_fifo); +} + +static uint32_t esp32_i2c_get_status_reg(Esp32I2CState* s) +{ + uint32_t res = 0; + res = FIELD_DP32(res, I2C_STATUS, BUS_BUSY, s->trans_ongoing); + res = FIELD_DP32(res, I2C_STATUS, RXFIFO_CNT, fifo8_num_used(&s->rx_fifo)); + res = FIELD_DP32(res, I2C_STATUS, TXFIFO_CNT, fifo8_num_used(&s->tx_fifo)); + return res; +} + +static void esp32_i2c_update_irq(Esp32I2CState * s) +{ + int irq_state = !!(s->int_raw_reg & s->int_ena_reg); + qemu_set_irq(s->irq, irq_state); +} + +static uint64_t esp32_i2c_read(void * opaque, hwaddr addr, unsigned int size) +{ + Esp32I2CState * s = Esp32_I2C(opaque); + + switch(addr) { + case A_I2C_CTR: + return s->ctr_reg; + case A_I2C_STATUS: + return esp32_i2c_get_status_reg(s); + case A_I2C_FIFO_DATA: { + if (fifo8_num_used(&s->rx_fifo) == 0) { + error_report("esp32_i2c: read I2C FIFO while it is empty"); + return 0xee; + } + uint8_t res = fifo8_pop(&s->rx_fifo); + return res; + } + case A_I2C_INT_RAW: + return s->int_raw_reg; + case A_I2C_INT_ENA: + return s->int_ena_reg; + case A_I2C_INT_ST: + return s->int_raw_reg & s->int_ena_reg; + case A_I2C_CMD ... (A_I2C_CMD + ESP32_I2C_CMD_COUNT * 4): + return s->cmd_reg[(addr - A_I2C_CMD) / 4]; + case A_I2C_TIMEOUT: + return s->timeout_reg; + case A_I2C_SDA_HOLD: + return s->sda_hold_reg; + case A_I2C_SDA_SAMPLE: + return s->sda_sample_reg; + case A_I2C_HIGH_PERIOD: + return s->high_period_reg; + case A_I2C_LOW_PERIOD: + return s->low_period_reg; + case A_I2C_START_HOLD: + return s->start_hold_reg; + case A_I2C_RSTART_SETUP: + return s->rstart_setup_reg; + case A_I2C_STOP_HOLD: + return s->stop_hold_reg; + case A_I2C_STOP_SETUP: + return s->stop_setup_reg; + default: + return 0; + } +} + +static void esp32_i2c_write(void * opaque, hwaddr addr, uint64_t value, unsigned int size) +{ + Esp32I2CState * s = Esp32_I2C(opaque); + + switch(addr) { + case A_I2C_CTR: + if (FIELD_EX32(value, I2C_CTR, MS_MODE) != 1) { + error_report("esp32_i2c: slave mode not implemented"); + } + if (FIELD_EX32(value, I2C_CTR, TRANS_START)) { + esp32_i2c_do_transaction(s); + value &= ~ R_I2C_CTR_TRANS_START_MASK; + } + s->ctr_reg = value; + break; + case A_I2C_FIFO_CONF: + if (FIELD_EX32(value, I2C_FIFO_CONF, NONFIFO_EN)) { + error_report("esp32_i2c: APB mode not implemented"); + } + if (FIELD_EX32(value, I2C_FIFO_CONF, RX_FIFO_RST)) { + fifo8_reset(&s->rx_fifo); + } + if (FIELD_EX32(value, I2C_FIFO_CONF, TX_FIFO_RST)) { + fifo8_reset(&s->tx_fifo); + } + break; + case A_I2C_FIFO_DATA: + if (fifo8_num_free(&s->tx_fifo) == 0) { + error_report("esp32_i2c: write to I2C TX FIFO while it is full"); + } else { + fifo8_push(&s->tx_fifo, value); + } + break; + case A_I2C_INT_CLR: + s->int_raw_reg &= ~value; + esp32_i2c_update_irq(s); + break; + case A_I2C_INT_ENA: + s->int_ena_reg = value; + esp32_i2c_update_irq(s); + break; + case A_I2C_CMD ... (A_I2C_CMD + ESP32_I2C_CMD_COUNT * 4): + s->cmd_reg[(addr - A_I2C_CMD) / 4] = value; + break; + case A_I2C_TIMEOUT: + s->timeout_reg = value; + break; + case A_I2C_SDA_HOLD: + s->sda_hold_reg = value; + break; + case A_I2C_SDA_SAMPLE: + s->sda_sample_reg = value; + break; + case A_I2C_HIGH_PERIOD: + s->high_period_reg = value; + break; + case A_I2C_LOW_PERIOD: + s->low_period_reg = value; + break; + case A_I2C_START_HOLD: + s->start_hold_reg = value; + break; + case A_I2C_RSTART_SETUP: + s->rstart_setup_reg = value; + break; + case A_I2C_STOP_HOLD: + s->stop_hold_reg = value; + break; + case A_I2C_STOP_SETUP: + s->stop_setup_reg = value; + break; + default: + break; + } +} + +static void esp32_i2c_do_transaction(Esp32I2CState * s) +{ + bool stop_or_end = false; + for (int i_cmd = 0; i_cmd < ESP32_I2C_CMD_COUNT && !stop_or_end; ++i_cmd) { + uint32_t cmd = s->cmd_reg[i_cmd]; + char opcode = FIELD_EX32(cmd, I2C_CMD, OPCODE); + switch (opcode) { + case I2C_OPCODE_RSTART: + i2c_end_transfer(s->bus); + s->trans_ongoing = false; + break; + case I2C_OPCODE_WRITE: { + size_t length = FIELD_EX32(cmd, I2C_CMD, BYTE_NUM); + if (!s->trans_ongoing) { + s->trans_ongoing = true; + uint8_t data = fifo8_pop(&s->tx_fifo); + uint8_t addr = data >> 1; + uint8_t is_read = data & 0x1; + if (i2c_start_transfer(s->bus, addr, is_read) != 0) { + /* NACK */ + if (FIELD_EX32(cmd, I2C_CMD, ACK_CHECK_EN) + && FIELD_EX32(cmd, I2C_CMD, ACK_EXP) == 0) { + s->int_raw_reg = FIELD_DP32(s->int_raw_reg, I2C_INT_RAW, ACK_ERR, 1); + stop_or_end = true; + } + s->trans_ongoing = false; + break; + } + s->int_raw_reg = FIELD_DP32(s->int_raw_reg, I2C_INT_RAW, ACK_ERR, 0); + length -= 1; + } + for (size_t nbytes = 0; nbytes < length; ++nbytes) { + uint8_t data = fifo8_pop(&s->tx_fifo); + i2c_send(s->bus, data); + } + break; + } + case I2C_OPCODE_READ: { + size_t length = FIELD_EX32(cmd, I2C_CMD, BYTE_NUM); + for (size_t nbytes = 0; nbytes < length; ++nbytes) { + if (fifo8_num_free(&s->rx_fifo) == 0) { + error_report("esp32_i2c: RX FIFO overflow"); + } else { + uint8_t data = i2c_recv(s->bus); + fifo8_push(&s->rx_fifo, data); + } + } + break; + } + case I2C_OPCODE_STOP: + i2c_end_transfer(s->bus); + s->trans_ongoing = false; + s->int_raw_reg = FIELD_DP32(s->int_raw_reg, I2C_INT_RAW, TRANS_COMPLETE, 1); + stop_or_end = true; + break; + case I2C_OPCODE_END: + s->int_raw_reg = FIELD_DP32(s->int_raw_reg, I2C_INT_RAW, END_DETECT, 1); + stop_or_end = true; + break; + default: + error_report("esp32_i2c: Invalid command %d opcode %d", i_cmd, opcode); + break; + } + s->cmd_reg[i_cmd] = FIELD_DP32(s->cmd_reg[i_cmd], I2C_CMD, DONE, 1); + } + esp32_i2c_update_irq(s); +} + +static const MemoryRegionOps esp32_i2c_ops = { + .read = esp32_i2c_read, + .write = esp32_i2c_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_i2c_init(Object * obj) +{ + Esp32I2CState *s = Esp32_I2C(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_i2c_ops, s, TYPE_ESP32_I2C, ESP32_I2C_MEM_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + + s->bus = i2c_init_bus(DEVICE(s), "i2c"); + + fifo8_create(&s->tx_fifo, ESP32_I2C_FIFO_LENGTH); + fifo8_create(&s->rx_fifo, ESP32_I2C_FIFO_LENGTH); +} + +static void esp32_i2c_class_init(ObjectClass * klass, void * data) +{ + DeviceClass * dc = DEVICE_CLASS(klass); + dc->reset = esp32_i2c_reset; +} + +static const TypeInfo esp32_i2c_type_info = { + .name = TYPE_ESP32_I2C, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32I2CState), + .instance_init = esp32_i2c_init, + .class_init = esp32_i2c_class_init, +}; + +static void esp32_i2c_register_types(void) +{ + type_register_static(&esp32_i2c_type_info); +} + +type_init(esp32_i2c_register_types) diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build index 3996564c25c6..31b924225657 100644 --- a/hw/i2c/meson.build +++ b/hw/i2c/meson.build @@ -15,6 +15,7 @@ i2c_ss.add(when: 'CONFIG_SMBUS_EEPROM', if_true: files('smbus_eeprom.c')) i2c_ss.add(when: 'CONFIG_ARM_SBCON_I2C', if_true: files('arm_sbcon_i2c.c')) i2c_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_i2c.c')) i2c_ss.add(when: 'CONFIG_PPC4XX', if_true: files('ppc4xx_i2c.c')) +i2c_ss.add(when: 'CONFIG_XTENSA_ESP32', if_true: files('esp32_i2c.c')) i2c_ss.add(when: 'CONFIG_PCA954X', if_true: files('i2c_mux_pca954x.c')) i2c_ss.add(when: 'CONFIG_PMBUS', if_true: files('pmbus_device.c')) softmmu_ss.add_all(when: 'CONFIG_I2C', if_true: i2c_ss) diff --git a/hw/misc/esp32_aes.c b/hw/misc/esp32_aes.c new file mode 100644 index 000000000000..a7f53eb7d7c4 --- /dev/null +++ b/hw/misc/esp32_aes.c @@ -0,0 +1,129 @@ +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32_aes.h" +#include "crypto/aes.h" + +#define ESP32_AES_REGS_SIZE (A_AES_ENDIAN_REG + 4) + +/* + * process the value of the AES_MODE_REG + */ +static void esp32_aes_mode(Esp32AesState *s, uint32_t mode_value) +{ + if ((mode_value == 0) || (mode_value == 1) || (mode_value == 2)) { + s->mode.type = ESP32_AES_ENCRYPTION_MODE; + } else { + s->mode.type = ESP32_AES_DECRYPTION_MODE; + } + if ((mode_value == 0) || (mode_value == 4)) { + s->mode.bits = 128; + } else if ((mode_value == 1) || (mode_value == 5)) { + s->mode.bits = 192; + } else { + s->mode.bits = 256; + } +} + +/* + * fill the full_key according to the mode bits + * encrypt/decrypt according to mode value + * set idle to 1 + */ +static void esp32_aes_start(Esp32AesState *s) +{ + AES_KEY aes_key; + uint32_t full_key[s->mode.bits / 32]; + memcpy(full_key, s->key, s->mode.bits / 8); + if (s->mode.type == ESP32_AES_ENCRYPTION_MODE) { + AES_set_encrypt_key((unsigned char *)full_key, s->mode.bits, &aes_key); + AES_encrypt((unsigned char *)s->text, (unsigned char *)s->text, &aes_key); + } else if (s->mode.type == ESP32_AES_DECRYPTION_MODE) { + AES_set_decrypt_key((unsigned char *)full_key, s->mode.bits, &aes_key); + AES_decrypt((unsigned char *)s->text, (unsigned char *)s->text, &aes_key); + } + s->aes_idle_reg = 1; +} + +static uint64_t esp32_aes_read(void *opaque, hwaddr addr, unsigned int size) +{ + Esp32AesState *s = ESP32_AES(opaque); + uint64_t r = 0; + switch (addr) { + case A_AES_TEXT_0_REG ... A_AES_TEXT_3_REG: + r = s->text[(addr - A_AES_TEXT_0_REG) / sizeof(uint32_t)]; + break; + case A_AES_IDLE_REG: + r = s->aes_idle_reg; + break; + } + return r; +} + + +static void esp32_aes_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + Esp32AesState *s = ESP32_AES(opaque); + switch (addr) { + case A_AES_TEXT_0_REG ... A_AES_TEXT_3_REG: + s->text[(addr - A_AES_TEXT_0_REG) / sizeof(uint32_t)] = value; + break; + case A_AES_KEY_0_REG ... A_AES_KEY_7_REG: + s->key[(addr - A_AES_KEY_0_REG) / sizeof(uint32_t)] = value; + break; + case A_AES_START_REG: + s->aes_idle_reg = 0; + esp32_aes_start(s); + break; + case A_AES_IDLE_REG: + s->aes_idle_reg = value; + break; + case A_AES_MODE_REG: + esp32_aes_mode(s, (uint32_t)value); + break; + } +} + +static const MemoryRegionOps esp32_aes_ops = { + .read = esp32_aes_read, + .write = esp32_aes_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_aes_reset(DeviceState *dev) +{ + Esp32AesState *s = ESP32_AES(dev); + s->aes_idle_reg = 0; +} + +static void esp32_aes_init(Object *obj) +{ + Esp32AesState *s = ESP32_AES(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_aes_ops, s, + TYPE_ESP32_AES, ESP32_AES_REGS_SIZE); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void esp32_aes_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32_aes_reset; +} + +static const TypeInfo esp32_aes_info = { + .name = TYPE_ESP32_AES, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32AesState), + .instance_init = esp32_aes_init, + .class_init = esp32_aes_class_init +}; + +static void esp32_aes_register_types(void) +{ + type_register_static(&esp32_aes_info); +} + +type_init(esp32_aes_register_types) diff --git a/hw/misc/esp32_ana.c b/hw/misc/esp32_ana.c new file mode 100644 index 000000000000..dc8da7064304 --- /dev/null +++ b/hw/misc/esp32_ana.c @@ -0,0 +1,72 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qemu/guest-random.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32_ana.h" + +int esp32_wifi_channel=0; + +static uint64_t esp32_ana_read(void *opaque, hwaddr addr, unsigned int size) +{ + Esp32AnaState *s = ESP32_ANA(opaque); + // printf("analog read for %016lX\n", addr); + uint32_t r = s->mem[addr/4]; + switch(addr) { + case 4: r= 0xFDFFFFFF; + break; + case 68: + case 76: + case 196: r=0xFFFFFFFF; + break; + } + return r; +} + +static void esp32_ana_write(void *opaque, hwaddr addr, uint64_t value, + unsigned int size) { + Esp32AnaState *s = ESP32_ANA(opaque); + if (addr == 196) { + int v = value&255; + if ((v % 10)==4) { + esp32_wifi_channel=(v/10)-1; + printf("esp32 wifi channel register = %d\n", esp32_wifi_channel); + } + } + s->mem[addr/4]=value; + // printf("analog write to %016lx, value=%016lx\n", addr, value); +} + +static const MemoryRegionOps esp32_ana_ops = { + .read = esp32_ana_read, + .write = esp32_ana_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_ana_init(Object *obj) +{ + Esp32AnaState *s = ESP32_ANA(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_ana_ops, s, + TYPE_ESP32_ANA, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + memset(s->mem,0,sizeof(s->mem)); +} + + +static const TypeInfo esp32_ana_info = { + .name = TYPE_ESP32_ANA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32AnaState), + .instance_init = esp32_ana_init, +}; + +static void esp32_ana_register_types(void) +{ + type_register_static(&esp32_ana_info); +} + +type_init(esp32_ana_register_types) diff --git a/hw/misc/esp32_crosscore_int.c b/hw/misc/esp32_crosscore_int.c new file mode 100644 index 000000000000..9b2c4fc55f83 --- /dev/null +++ b/hw/misc/esp32_crosscore_int.c @@ -0,0 +1,91 @@ +/* + * ESP32 Cross-core interrupt + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/registerfields.h" +#include "hw/qdev-properties.h" +#include "hw/misc/esp32_reg.h" +#include "hw/misc/esp32_crosscore_int.h" + + +static uint64_t esp32_crosscore_int_read(void *opaque, hwaddr addr, unsigned int size) +{ + return 0; +} + +static void esp32_crosscore_int_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + Esp32CrosscoreInt *s = ESP32_CROSSCORE_INT(opaque); + int index = addr / 4; + assert(index < s->n_irqs); + qemu_set_irq(s->irqs[index], value & 0x1); +} + +static const MemoryRegionOps esp32_crosscore_int_ops = { + .read = esp32_crosscore_int_read, + .write = esp32_crosscore_int_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_crosscore_int_realize(DeviceState *dev, Error **errp) +{ + Esp32CrosscoreInt *s = ESP32_CROSSCORE_INT(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + s->irqs = g_malloc0_n(s->n_irqs, sizeof(qemu_irq)); + assert(s->irqs); + for (int i = 0; i < s->n_irqs; ++i) { + sysbus_init_irq(sbd, &s->irqs[i]); + } + + memory_region_init_io(&s->iomem, OBJECT(dev), &esp32_crosscore_int_ops, s, + TYPE_ESP32_CROSSCORE_INT, + s->n_irqs * sizeof(uint32_t)); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void esp32_crosscore_int_init(Object *obj) +{ + +} + +static Property esp32_crosscore_int_properties[] = { + DEFINE_PROP_INT32("n_irqs", Esp32CrosscoreInt, n_irqs, 4), + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32_crosscore_int_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = esp32_crosscore_int_realize; + device_class_set_props(dc, esp32_crosscore_int_properties); +} + +static const TypeInfo esp32_crosscore_int_info = { + .name = TYPE_ESP32_CROSSCORE_INT, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32CrosscoreInt), + .instance_init = esp32_crosscore_int_init, + .class_init = esp32_crosscore_int_class_init +}; + +static void esp32_crosscore_int_register_types(void) +{ + type_register_static(&esp32_crosscore_int_info); +} + +type_init(esp32_crosscore_int_register_types) diff --git a/hw/misc/esp32_dport.c b/hw/misc/esp32_dport.c new file mode 100644 index 000000000000..d73b6281a230 --- /dev/null +++ b/hw/misc/esp32_dport.c @@ -0,0 +1,475 @@ +/* + * ESP32 "DPORT" device + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "hw/registerfields.h" +#include "hw/boards.h" +#include "hw/misc/esp32_reg.h" +#include "hw/misc/esp32_dport.h" + +#include "hw/misc/esp32_flash_enc.h" +#include "hw/nvram/esp32_efuse.h" + + +#define ESP32_DPORT_SIZE (DR_REG_DPORT_APB_BASE - DR_REG_DPORT_BASE) + +#define MMU_RANGE_SIZE (ESP32_CACHE_PAGES_PER_REGION * sizeof(uint32_t)) +#define MMU_RANGE_LAST (MMU_RANGE_SIZE - sizeof(uint32_t)) + +#define PRO_DROM0_MMU_FIRST (DR_REG_FLASH_MMU_TABLE_PRO - DR_REG_DPORT_BASE) +#define PRO_DROM0_MMU_LAST (PRO_DROM0_MMU_FIRST + MMU_RANGE_LAST) +#define PRO_IRAM0_MMU_FIRST (DR_REG_FLASH_MMU_TABLE_PRO - DR_REG_DPORT_BASE + MMU_RANGE_SIZE) +#define PRO_IRAM0_MMU_LAST (PRO_IRAM0_MMU_FIRST + MMU_RANGE_LAST) +#define APP_DROM0_MMU_FIRST (DR_REG_FLASH_MMU_TABLE_APP - DR_REG_DPORT_BASE) +#define APP_DROM0_MMU_LAST (APP_DROM0_MMU_FIRST + MMU_RANGE_LAST) +#define APP_IRAM0_MMU_FIRST (DR_REG_FLASH_MMU_TABLE_APP - DR_REG_DPORT_BASE + MMU_RANGE_SIZE) +#define APP_IRAM0_MMU_LAST (APP_IRAM0_MMU_FIRST + MMU_RANGE_LAST) +#define MMU_ENTRY_MASK 0x1ff + +static void esp32_cache_state_update(Esp32CacheState* cs); +static void esp32_cache_data_sync(Esp32CacheRegionState* crs); +static void esp32_cache_invalidate_all_entries(Esp32CacheRegionState* crs); + +static inline uint32_t get_mmu_entry(Esp32CacheRegionState* crs, hwaddr base, hwaddr addr) +{ + return crs->mmu_table[(addr - base)/sizeof(uint32_t)] & MMU_ENTRY_MASK; +} + +static inline void set_mmu_entry(Esp32CacheRegionState* crs, hwaddr base, hwaddr addr, uint64_t val) +{ + uint32_t old_val = crs->mmu_table[(addr - base)/sizeof(uint32_t)]; + if (val != old_val) { + crs->mmu_table[(addr - base)/sizeof(uint32_t)] = (val & MMU_ENTRY_MASK) | ESP32_CACHE_MMU_ENTRY_CHANGED; + } +} + +static uint64_t esp32_dport_read(void *opaque, hwaddr addr, unsigned int size) +{ + Esp32DportState *s = ESP32_DPORT(opaque); + uint64_t r = 0; + switch (addr) { + case A_DPORT_APPCPU_RESET: + r = s->appcpu_reset_state; + break; + case A_DPORT_APPCPU_CLK: + r = s->appcpu_clkgate_state; + break; + case A_DPORT_APPCPU_RUNSTALL: + r = s->appcpu_stall_state; + break; + case A_DPORT_APPCPU_BOOT_ADDR: + r = s->appcpu_boot_addr; + break; + case A_DPORT_CPU_PER_CONF: + r = s->cpuperiod_sel; + break; + case A_DPORT_PRO_CACHE_CTRL: + r = s->cache_state[0].cache_ctrl_reg; + break; + case A_DPORT_PRO_CACHE_CTRL1: + r = s->cache_state[0].cache_ctrl1_reg; + break; + case A_DPORT_APP_CACHE_CTRL: + r = s->cache_state[1].cache_ctrl_reg; + break; + case A_DPORT_APP_CACHE_CTRL1: + r = s->cache_state[1].cache_ctrl1_reg; + break; + case A_DPORT_PRO_DCACHE_DBUG0: + case A_DPORT_APP_DCACHE_DBUG0: + /* in idle state */ + r = FIELD_DP32(0, DPORT_PRO_DCACHE_DBUG0, CACHE_STATE, 1); + break; + case A_DPORT_CACHE_IA_INT_EN: + r = s->cache_ill_trap_en_reg; + break; + case A_DPORT_PRO_DCACHE_DBUG3: + r = 0; + r = FIELD_DP32(r, DPORT_PRO_DCACHE_DBUG3, IA_INT_DROM0, s->cache_state[0].drom0.illegal_access_status); + r = FIELD_DP32(r, DPORT_PRO_DCACHE_DBUG3, IA_INT_IRAM0, s->cache_state[0].iram0.illegal_access_status); + break; + case A_DPORT_APP_DCACHE_DBUG3: + r = 0; + r = FIELD_DP32(r, DPORT_APP_DCACHE_DBUG3, IA_INT_DROM0, s->cache_state[1].drom0.illegal_access_status); + r = FIELD_DP32(r, DPORT_APP_DCACHE_DBUG3, IA_INT_IRAM0, s->cache_state[1].iram0.illegal_access_status); + break; + case PRO_DROM0_MMU_FIRST ... PRO_DROM0_MMU_LAST: + r = get_mmu_entry(&s->cache_state[0].drom0, PRO_DROM0_MMU_FIRST, addr); + break; + case PRO_IRAM0_MMU_FIRST ... PRO_IRAM0_MMU_LAST: + r = get_mmu_entry(&s->cache_state[0].iram0, PRO_IRAM0_MMU_FIRST, addr); + break; + case APP_DROM0_MMU_FIRST ... APP_DROM0_MMU_LAST: + r = get_mmu_entry(&s->cache_state[1].drom0, APP_DROM0_MMU_FIRST, addr); + break; + case APP_IRAM0_MMU_FIRST ... APP_IRAM0_MMU_LAST: + r = get_mmu_entry(&s->cache_state[1].iram0, APP_IRAM0_MMU_FIRST, addr); + break; + case A_DPORT_SLAVE_SPI_CONFIG: + r = s->slave_spi_config_reg; + break; + } + + return r; +} + +static void esp32_dport_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + Esp32DportState *s = ESP32_DPORT(opaque); + bool old_state; + uint32_t old_val; + switch (addr) { + case A_DPORT_APPCPU_RESET: + old_state = s->appcpu_reset_state; + s->appcpu_reset_state = value & 1; + if (old_state && !s->appcpu_reset_state) { + qemu_irq_pulse(s->appcpu_reset_req); + } + break; + case A_DPORT_APPCPU_CLK: + s->appcpu_clkgate_state = value & 1; + qemu_set_irq(s->appcpu_stall_req, s->appcpu_stall_state || !s->appcpu_clkgate_state); + break; + case A_DPORT_APPCPU_RUNSTALL: + s->appcpu_stall_state = value & 1; + qemu_set_irq(s->appcpu_stall_req, s->appcpu_stall_state || !s->appcpu_clkgate_state); + break; + case A_DPORT_APPCPU_BOOT_ADDR: + s->appcpu_boot_addr = value; + break; + case A_DPORT_CPU_PER_CONF: + s->cpuperiod_sel = value & R_DPORT_CPU_PER_CONF_CPUPERIOD_SEL_MASK; + qemu_irq_pulse(s->clk_update_req); + break; + case A_DPORT_PRO_CACHE_CTRL: + if (FIELD_EX32(value, DPORT_PRO_CACHE_CTRL, CACHE_FLUSH_ENA)) { + value |= R_DPORT_PRO_CACHE_CTRL_CACHE_FLUSH_DONE_MASK; + value &= ~R_DPORT_PRO_CACHE_CTRL_CACHE_FLUSH_ENA_MASK; + esp32_cache_invalidate_all_entries(&s->cache_state[0].drom0); + esp32_cache_data_sync(&s->cache_state[0].drom0); + esp32_cache_invalidate_all_entries(&s->cache_state[0].iram0); + esp32_cache_data_sync(&s->cache_state[0].iram0); + } + old_val = s->cache_state[0].cache_ctrl_reg; + s->cache_state[0].cache_ctrl_reg = value; + if (value != old_val) { + esp32_cache_state_update(&s->cache_state[0]); + } + break; + case A_DPORT_PRO_CACHE_CTRL1: + old_val = s->cache_state[0].cache_ctrl1_reg; + s->cache_state[0].cache_ctrl1_reg = value; + if (value != old_val) { + esp32_cache_state_update(&s->cache_state[0]); + } + break; + case A_DPORT_APP_CACHE_CTRL: + if (FIELD_EX32(value, DPORT_APP_CACHE_CTRL, CACHE_FLUSH_ENA)) { + value |= R_DPORT_APP_CACHE_CTRL_CACHE_FLUSH_DONE_MASK; + value &= ~R_DPORT_APP_CACHE_CTRL_CACHE_FLUSH_ENA_MASK; + esp32_cache_invalidate_all_entries(&s->cache_state[1].drom0); + esp32_cache_data_sync(&s->cache_state[1].drom0); + esp32_cache_invalidate_all_entries(&s->cache_state[1].iram0); + esp32_cache_data_sync(&s->cache_state[1].iram0); + } + old_val = s->cache_state[1].cache_ctrl_reg; + s->cache_state[1].cache_ctrl_reg = value; + if (value != old_val) { + esp32_cache_state_update(&s->cache_state[1]); + } + break; + case A_DPORT_APP_CACHE_CTRL1: + old_val = s->cache_state[1].cache_ctrl1_reg; + s->cache_state[1].cache_ctrl1_reg = value; + if (value != old_val) { + esp32_cache_state_update(&s->cache_state[1]); + } + break; + case A_DPORT_CACHE_IA_INT_EN: + s->cache_ill_trap_en_reg = value; + s->cache_state[0].drom0.illegal_access_trap_en = (FIELD_EX32(value, DPORT_CACHE_IA_INT_EN, IA_INT_PRO_DROM0)); + s->cache_state[0].iram0.illegal_access_trap_en = (FIELD_EX32(value, DPORT_CACHE_IA_INT_EN, IA_INT_PRO_IRAM0)); + s->cache_state[1].drom0.illegal_access_trap_en = (FIELD_EX32(value, DPORT_CACHE_IA_INT_EN, IA_INT_APP_DROM0)); + s->cache_state[1].iram0.illegal_access_trap_en = (FIELD_EX32(value, DPORT_CACHE_IA_INT_EN, IA_INT_APP_IRAM0)); + s->cache_state[0].dram1.illegal_access_trap_en = (FIELD_EX32(value, DPORT_CACHE_IA_INT_EN, IA_INT_PRO_DRAM1)); + s->cache_state[1].dram1.illegal_access_trap_en = (FIELD_EX32(value, DPORT_CACHE_IA_INT_EN, IA_INT_APP_DRAM1)); + break; + case PRO_DROM0_MMU_FIRST ... PRO_DROM0_MMU_LAST: + set_mmu_entry(&s->cache_state[0].drom0, PRO_DROM0_MMU_FIRST, addr, value); + break; + case PRO_IRAM0_MMU_FIRST ... PRO_IRAM0_MMU_LAST: + set_mmu_entry(&s->cache_state[0].iram0, PRO_IRAM0_MMU_FIRST, addr, value); + break; + case APP_DROM0_MMU_FIRST ... APP_DROM0_MMU_LAST: + set_mmu_entry(&s->cache_state[1].drom0, APP_DROM0_MMU_FIRST, addr, value); + break; + case APP_IRAM0_MMU_FIRST ... APP_IRAM0_MMU_LAST: + set_mmu_entry(&s->cache_state[1].iram0, APP_IRAM0_MMU_FIRST, addr, value); + break; + case A_DPORT_SLAVE_SPI_CONFIG: + s->slave_spi_config_reg = value; + qemu_set_irq(s->flash_enc_en_gpio, FIELD_EX32(value, DPORT_SLAVE_SPI_CONFIG, SLAVE_SPI_ENCRYPT_ENABLE)); + qemu_set_irq(s->flash_dec_en_gpio, FIELD_EX32(value, DPORT_SLAVE_SPI_CONFIG, SLAVE_SPI_DECRYPT_ENABLE)); + break; + } +} + +static const MemoryRegionOps esp32_dport_ops = { + .read = esp32_dport_read, + .write = esp32_dport_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_cache_data_sync(Esp32CacheRegionState* crs) +{ + if (crs->cache->dport->flash_blk == NULL) { + return; + } + + Esp32FlashEncryptionState * flash_enc = esp32_flash_encryption_find(); + bool decrypt = (flash_enc != NULL && esp32_flash_decryption_enabled(flash_enc)); + + uint8_t* cache_data = (uint8_t*) memory_region_get_ram_ptr(&crs->mem); + int n = 0; + for (int i = 0; i < ESP32_CACHE_PAGES_PER_REGION; ++i) { + uint32_t* cache_page = (uint32_t*) (cache_data + i * ESP32_CACHE_PAGE_SIZE); + uint32_t mmu_entry = crs->mmu_table[i]; + if (!(mmu_entry & ESP32_CACHE_MMU_ENTRY_CHANGED)) { + continue; + } + mmu_entry &= MMU_ENTRY_MASK; + if (mmu_entry & ESP32_CACHE_MMU_INVALID_VAL) { + uint32_t fill_val = crs->illegal_access_retval; + for (int word = 0; word < ESP32_CACHE_PAGE_SIZE / sizeof(uint32_t); ++word) { + cache_page[word] = fill_val; + } + } else { + uint32_t phys_addr = mmu_entry * ESP32_CACHE_PAGE_SIZE; + blk_pread(crs->cache->dport->flash_blk, phys_addr, ESP32_CACHE_PAGE_SIZE, cache_page, 0); + if (decrypt) { + esp32_flash_decrypt_inplace(flash_enc, phys_addr, cache_page, ESP32_CACHE_PAGE_SIZE/4); + } + } + crs->mmu_table[i] &= ~ESP32_CACHE_MMU_ENTRY_CHANGED; + n++; + } + memory_region_flush_rom_device(&crs->mem, 0, ESP32_CACHE_REGION_SIZE); +} + +static void esp32_cache_invalidate_all_entries(Esp32CacheRegionState* crs) +{ + for (int i = 0; i < ESP32_CACHE_PAGES_PER_REGION; ++i) { + crs->mmu_table[i] |= ESP32_CACHE_MMU_ENTRY_CHANGED; + } +} + +static void esp32_cache_state_update(Esp32CacheState* cs) +{ + bool cache_enabled = FIELD_EX32(cs->cache_ctrl_reg, DPORT_PRO_CACHE_CTRL, CACHE_ENA) != 0; + + bool drom0_enabled = cache_enabled && + FIELD_EX32(cs->cache_ctrl1_reg, DPORT_PRO_CACHE_CTRL1, MASK_DROM0) == 0; + if (!cs->drom0.mem.enabled && drom0_enabled) { + esp32_cache_data_sync(&cs->drom0); + } + memory_region_set_enabled(&cs->drom0.mem, drom0_enabled); + + bool iram0_enabled = cache_enabled && + FIELD_EX32(cs->cache_ctrl1_reg, DPORT_PRO_CACHE_CTRL1, MASK_IRAM0) == 0; + if (!cs->iram0.mem.enabled && iram0_enabled) { + esp32_cache_data_sync(&cs->iram0); + } + memory_region_set_enabled(&cs->iram0.mem, iram0_enabled); + + if (cs->dport->has_psram) { + bool dram1_enabled = cache_enabled && + FIELD_EX32(cs->cache_ctrl1_reg, DPORT_PRO_CACHE_CTRL1, MASK_DRAM1) == 0; + memory_region_set_enabled(&cs->dram1.mem, dram1_enabled); + } +} + +static void esp32_cache_region_reset(Esp32CacheRegionState *crs) +{ + for (int i = 0; i < ESP32_CACHE_PAGES_PER_REGION; ++i) { + crs->mmu_table[i] = ESP32_CACHE_MMU_ENTRY_CHANGED; + } + crs->illegal_access_trap_en = false; +} + +static void esp32_cache_reset(Esp32CacheState *cs) +{ + esp32_cache_region_reset(&cs->drom0); + esp32_cache_region_reset(&cs->iram0); +} + +static uint64_t esp32_cache_ill_read(void *opaque, hwaddr addr, unsigned int size) +{ + Esp32CacheRegionState *crs = (Esp32CacheRegionState*) opaque; + uint32_t ill_data[] = { crs->illegal_access_retval, crs->illegal_access_retval }; + uint32_t result; + memcpy(&result, ((uint8_t*) ill_data) + (addr % 4), size); + if (crs->illegal_access_trap_en) { + crs->illegal_access_status = true; + qemu_irq_raise(crs->cache->dport->cache_ill_irq); + } + return result; +} + +static void esp32_cache_ill_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ +} + +static bool esp32_cache_ill_accepts(void *opaque, hwaddr addr, + unsigned size, bool is_write, + MemTxAttrs attrs) +{ + return !is_write; +} + + +void esp32_dport_clear_ill_trap_state(Esp32DportState* s) +{ + s->cache_state[0].drom0.illegal_access_status = false; + s->cache_state[1].drom0.illegal_access_status = false; + s->cache_state[0].iram0.illegal_access_status = false; + s->cache_state[1].iram0.illegal_access_status = false; + s->cache_state[0].dram1.illegal_access_status = false; + s->cache_state[1].dram1.illegal_access_status = false; + qemu_irq_lower(s->cache_ill_irq); +} + +static const MemoryRegionOps esp32_cache_ops = { + .write = NULL, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid.accepts = esp32_cache_ill_accepts, +}; + + +static const MemoryRegionOps esp32_cache_ill_trap_ops = { + .read = esp32_cache_ill_read, + .write = esp32_cache_ill_write, +}; + +static void esp32_dport_reset(DeviceState *dev) +{ + Esp32DportState *s = ESP32_DPORT(dev); + + s->appcpu_boot_addr = 0; + s->appcpu_clkgate_state = false; + s->appcpu_reset_state = true; + s->appcpu_stall_state = false; + s->cache_ill_trap_en_reg = 0; + esp32_cache_reset(&s->cache_state[0]); + esp32_cache_reset(&s->cache_state[1]); + qemu_irq_lower(s->appcpu_stall_req); +} + +static void esp32_dport_realize(DeviceState *dev, Error **errp) +{ + Esp32DportState *s = ESP32_DPORT(dev); + MachineState *ms = MACHINE(qdev_get_machine()); + + s->cpu_count = ms->smp.cpus; +} + +static void esp32_cache_init_region(Esp32CacheState *cs, + Esp32CacheRegionState *crs, + Esp32CacheRegionType type, + const char* name, hwaddr base, + uint32_t illegal_access_retval) +{ + char desc[16]; + crs->cache = cs; + crs->type = type; + crs->base = base; + crs->illegal_access_retval = illegal_access_retval; + snprintf(desc, sizeof(desc), "cpu%d-%s", cs->core_id, name); + if (type == ESP32_DCACHE_PSRAM) { + memory_region_init_ram(&crs->mem, OBJECT(cs->dport), desc, + ESP32_CACHE_REGION_SIZE, &error_abort); + } else { + memory_region_init_rom_device(&crs->mem, OBJECT(cs->dport), + &esp32_cache_ops, crs, + desc, ESP32_CACHE_REGION_SIZE, &error_abort); + } + + snprintf(desc, sizeof(desc), "cpu%d-%s-ill", cs->core_id, name); + memory_region_init_io(&crs->illegal_access_trap_mem, OBJECT(cs->dport), + &esp32_cache_ill_trap_ops, crs, + desc, ESP32_CACHE_REGION_SIZE); +} + +static void esp32_dport_init(Object *obj) +{ + Esp32DportState *s = ESP32_DPORT(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_dport_ops, s, + TYPE_ESP32_DPORT, ESP32_DPORT_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + + for (int i = 0; i < ESP32_CPU_COUNT; ++i) { + Esp32CacheState* cs = &s->cache_state[i]; + cs->core_id = i; + cs->dport = s; + esp32_cache_init_region(cs, &cs->drom0, ESP32_DCACHE_FLASH, "drom0", + 0x3F400000, 0xbaadbaad); + esp32_cache_init_region(cs, &cs->iram0, ESP32_ICACHE_FLASH, "iram0", + 0x40000000, 0x00000000); + esp32_cache_init_region(cs, &cs->dram1, ESP32_DCACHE_PSRAM, "dram1", + 0x3F800000, 0xbaadbaad); + } + + qdev_init_gpio_out_named(DEVICE(sbd), &s->appcpu_stall_req, ESP32_DPORT_APPCPU_STALL_GPIO, 1); + qdev_init_gpio_out_named(DEVICE(sbd), &s->appcpu_reset_req, ESP32_DPORT_APPCPU_RESET_GPIO, 1); + qdev_init_gpio_out_named(DEVICE(sbd), &s->clk_update_req, ESP32_DPORT_CLK_UPDATE_GPIO, 1); + qdev_init_gpio_out_named(DEVICE(sbd), &s->cache_ill_irq, ESP32_DPORT_CACHE_ILL_IRQ_GPIO, 1); + qdev_init_gpio_out_named(DEVICE(sbd), &s->flash_enc_en_gpio, ESP32_DPORT_FLASH_ENC_EN_GPIO, 1); + qdev_init_gpio_out_named(DEVICE(sbd), &s->flash_dec_en_gpio, ESP32_DPORT_FLASH_DEC_EN_GPIO, 1); +} + +static Property esp32_dport_properties[] = { + DEFINE_PROP_DRIVE("flash", Esp32DportState, flash_blk), + DEFINE_PROP_BOOL("has_psram", Esp32DportState, has_psram, false), + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32_dport_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32_dport_reset; + dc->realize = esp32_dport_realize; + device_class_set_props(dc, esp32_dport_properties); +} + +static const TypeInfo esp32_dport_info = { + .name = TYPE_ESP32_DPORT, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32DportState), + .instance_init = esp32_dport_init, + .class_init = esp32_dport_class_init +}; + +static void esp32_dport_register_types(void) +{ + type_register_static(&esp32_dport_info); +} + +type_init(esp32_dport_register_types) diff --git a/hw/misc/esp32_fe.c b/hw/misc/esp32_fe.c new file mode 100644 index 000000000000..1de52d4cce9b --- /dev/null +++ b/hw/misc/esp32_fe.c @@ -0,0 +1,56 @@ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qemu/guest-random.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32_fe.h" + +static uint64_t esp32_fe_read(void *opaque, hwaddr addr, unsigned int size) +{ + uint32_t r = 0; + Esp32FeState *s = ESP32_FE(opaque); + r = s->mem[addr/4]; + if (addr == 0x7c) { + r = 0xffffffff; + } + return r; +} + +static void esp32_fe_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size) { + Esp32FeState *s = ESP32_FE(opaque); + s->mem[addr/4] = (uint32_t)value; +} + +static const MemoryRegionOps esp32_fe_ops = { + .read = esp32_fe_read, + .write = esp32_fe_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_fe_init(Object *obj) +{ + Esp32FeState *s = ESP32_FE(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_fe_ops, s, TYPE_ESP32_FE, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + memset(s->mem, 0, sizeof(s->mem)); +} + + +static const TypeInfo esp32_fe_info = { + .name = TYPE_ESP32_FE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32FeState), + .instance_init = esp32_fe_init, +}; + +static void esp32_fe_register_types(void) +{ + type_register_static(&esp32_fe_info); +} + +type_init(esp32_fe_register_types) diff --git a/hw/misc/esp32_flash_enc.c b/hw/misc/esp32_flash_enc.c new file mode 100644 index 000000000000..0ef9fef0c5c2 --- /dev/null +++ b/hw/misc/esp32_flash_enc.c @@ -0,0 +1,271 @@ +/* + * ESP32 flash encryption + * + * Copyright (c) 2020 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "crypto/cipher.h" +#include "hw/misc/esp32_flash_enc.h" +#include "hw/nvram/esp32_efuse.h" + +#define FLASH_ENCRYPTION_KEY_WORDS 8 +#define FLASH_ENCRYPTION_DATA_WORDS 4 + +static void esp32_flash_encryption_op(Esp32FlashEncryptionState *s); + +static uint64_t esp32_flash_encryption_read(void *opaque, hwaddr addr, + unsigned int size) +{ + Esp32FlashEncryptionState *s = ESP32_FLASH_ENCRYPTION(opaque); + switch (addr) { + case A_FLASH_ENCRYPTION_DONE: + return s->encryption_done; + } + return 0; +} + +static void esp32_flash_encryption_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + Esp32FlashEncryptionState *s = ESP32_FLASH_ENCRYPTION(opaque); + + switch (addr) { + case A_FLASH_ENCRYPTION_BUFFER_0 ... A_FLASH_ENCRYPTION_BUFFER_7: + s->buffer_reg[(addr - A_FLASH_ENCRYPTION_BUFFER_0) / 4] = value; + break; + + case A_FLASH_ENCRYPTION_START: + if (FIELD_EX32(value, FLASH_ENCRYPTION_START, START)) { + esp32_flash_encryption_op(s); + } + s->encryption_done = true; + break; + + case A_FLASH_ENCRYPTION_ADDRESS: + s->address_reg = value; + break; + + case A_FLASH_ENCRYPTION_DONE: + if (FIELD_EX32(value, FLASH_ENCRYPTION_DONE, DONE) == 0) { + s->encryption_done = false; + } + break; + } +} + +static const MemoryRegionOps esp32_flash_encryption_ops = { + .read = esp32_flash_encryption_read, + .write = esp32_flash_encryption_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +bool esp32_flash_encryption_enabled(struct Esp32FlashEncryptionState *s) +{ + /* Logic from ESP32 Technical Reference Manual section 25.3.2 */ + if (s->dl_mode) { + return s->encrypt_enable_reg && !s->dl_mode_enc_disabled; + } else { + return s->encrypt_enable_reg; + } +} + +bool esp32_flash_decryption_enabled(struct Esp32FlashEncryptionState *s) +{ + /* Logic from ESP32 Technical Reference Manual section 25.3.3 */ + if (s->dl_mode) { + return s->decrypt_enable_reg && !s->dl_mode_dec_disabled; + } else { + return s->efuse_encrypt_enabled; + } +} + +static void esp32_flash_encryption_key_tweak(struct Esp32FlashEncryptionState *s, + size_t offset, const uint32_t *in_key, uint32_t *out_key) +{ + uint32_t offset_5 = offset >> 5; + uint32_t offset_5_8 = (offset_5) & 0xf; + uint32_t offset_5_10 = (offset_5) & 0x3f; + uint32_t offset_5_12 = (offset_5) & 0xff; + uint32_t offset_5_14 = (offset_5) & 0x3ff; + uint32_t offset_5_23 = (offset_5) & 0x7ffff; + + uint32_t key_tweak[FLASH_ENCRYPTION_KEY_WORDS] = { + (offset_5_23 >> 6) | (offset_5_23 << 13), + (offset_5_14 >> 3) | (offset_5_23 << 7) | (offset_5_23 << 26), + (offset_5_23 >> 9) | (offset_5_23 << 10) | (offset_5_14 << 29), + (offset_5_12 >> 4) | (offset_5_23 << 4) | (offset_5_23 << 23), + (offset_5_23 >> 10) | (offset_5_23 << 9) | (offset_5_12 << 28), + (offset_5_10 >> 3) | (offset_5_23 << 3) | (offset_5_23 << 22), + (offset_5_23 >> 9) | (offset_5_23 << 10) | (offset_5_10 << 29), + (offset_5_8) | (offset_5_23 << 4) | (offset_5_23 << 23) + }; + + for (size_t i = 0; i < FLASH_ENCRYPTION_KEY_WORDS; ++i) { + out_key[i] = in_key[i] ^ bswap32(key_tweak[i]); + } +} + +static void reverse_key_byte_order(const uint32_t* src, uint32_t* dst) +{ + assert( src != dst ); + for (size_t i = 0; i < FLASH_ENCRYPTION_KEY_WORDS; ++i) { + dst[i] = bswap32(src[FLASH_ENCRYPTION_KEY_WORDS - i - 1]); + } +} + +static void reverse_data_byte_order(const uint32_t* src, uint32_t* dst) +{ + assert( src != dst ); + for (size_t i = 0; i < FLASH_ENCRYPTION_DATA_WORDS; ++i) { + dst[i] = bswap32(src[FLASH_ENCRYPTION_DATA_WORDS - i - 1]); + } +} + +static void esp32_flash_encryption_op(struct Esp32FlashEncryptionState *s) +{ + uint32_t tweaked_key[FLASH_ENCRYPTION_KEY_WORDS]; + uint32_t reversed_key[FLASH_ENCRYPTION_KEY_WORDS]; + uint32_t reversed_data[FLASH_ENCRYPTION_DATA_WORDS]; + uint32_t encrypted_data[FLASH_ENCRYPTION_DATA_WORDS]; + + memset(s->encrypted_buffer, 0, sizeof(s->encrypted_buffer)); + reverse_key_byte_order(s->efuse_key, reversed_key); + esp32_flash_encryption_key_tweak(s, s->address_reg, reversed_key, tweaked_key); + QCryptoCipher *cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_256, QCRYPTO_CIPHER_MODE_ECB, (const uint8_t*) tweaked_key, FLASH_ENCRYPTION_KEY_WORDS * 4, &error_abort); + for (size_t total_words = 0; total_words < ARRAY_SIZE(s->buffer_reg); total_words += FLASH_ENCRYPTION_DATA_WORDS) { + reverse_data_byte_order(s->buffer_reg + total_words, reversed_data); + qcrypto_cipher_decrypt(cipher, reversed_data, encrypted_data, sizeof(s->buffer_reg), &error_abort); + reverse_data_byte_order(encrypted_data, s->encrypted_buffer + total_words); + } + qcrypto_cipher_free(cipher); +} + +void esp32_flash_encryption_get_result(struct Esp32FlashEncryptionState* s, uint32_t* dst, size_t dst_words) +{ + assert(dst_words * 4 == sizeof(s->encrypted_buffer)); + memcpy(dst, s->encrypted_buffer, sizeof(s->encrypted_buffer)); +} + +void esp32_flash_decrypt_inplace(struct Esp32FlashEncryptionState* s, size_t flash_addr, uint32_t* data, size_t words) +{ + assert(flash_addr % 32 == 0); + assert(words % FLASH_ENCRYPTION_DATA_WORDS == 0); + uint32_t tweaked_key[FLASH_ENCRYPTION_KEY_WORDS]; + uint32_t reversed_key[FLASH_ENCRYPTION_KEY_WORDS]; + uint32_t reversed_data[FLASH_ENCRYPTION_DATA_WORDS]; + uint32_t decrypted_data[FLASH_ENCRYPTION_DATA_WORDS]; + + reverse_key_byte_order(s->efuse_key, reversed_key); + for (size_t pos = 0; pos < words; pos += FLASH_ENCRYPTION_DATA_WORDS) { + uint32_t offset = flash_addr + pos * 4; + esp32_flash_encryption_key_tweak(s, offset, reversed_key, tweaked_key); + QCryptoCipher *cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_256, QCRYPTO_CIPHER_MODE_ECB, (const uint8_t*) tweaked_key, FLASH_ENCRYPTION_KEY_WORDS * 4, &error_abort); + reverse_data_byte_order(data + pos, reversed_data); + qcrypto_cipher_encrypt(cipher, reversed_data, decrypted_data, sizeof(decrypted_data), &error_abort); + reverse_data_byte_order(decrypted_data, data + pos); + qcrypto_cipher_free(cipher); + } +} + +static void esp32_flash_encryption_on_dl_mode_change(void *opaque, int n, + int level) +{ + Esp32FlashEncryptionState *s = ESP32_FLASH_ENCRYPTION(opaque); + s->dl_mode = !!level; +} + +static void esp32_flash_encryption_on_enc_enable_change(void *opaque, int n, + int level) +{ + Esp32FlashEncryptionState *s = ESP32_FLASH_ENCRYPTION(opaque); + s->encrypt_enable_reg = !!level; +} + +static void esp32_flash_encryption_on_dec_enable_change(void *opaque, int n, + int level) +{ + Esp32FlashEncryptionState *s = ESP32_FLASH_ENCRYPTION(opaque); + s->decrypt_enable_reg = !!level; +} + +static void esp32_flash_encryption_on_efuse_update(void *opaque, int n, + int level) +{ + if (!level) { + return; + } + Esp32FlashEncryptionState *s = ESP32_FLASH_ENCRYPTION(opaque); + Esp32EfuseState *efuse = esp32_efuse_find(); + /* Odd number of bits in flash_crypt_cnt indicates that flash encryption is enabled */ + s->efuse_encrypt_enabled = (ctpop32(efuse->efuse_rd.blk0_d0.flash_crypt_cnt) % 2) == 1; + uint32_t flash_crypt_config = efuse->efuse_rd.blk0_d5.flash_crypt_config; + if (s->efuse_encrypt_enabled && flash_crypt_config != 0xf) { + qemu_log("%s: Unsupported value of flash_crypt_config: 0x%x\n", __func__, flash_crypt_config); + } + if (efuse->efuse_rd.blk0_d6.coding_scheme != 0) { + qemu_log("%s: Unsupported value of coding_scheme: 0x%x\n", + __func__, efuse->efuse_rd.blk0_d6.coding_scheme); + } + /* Copy the key */ + memcpy(s->efuse_key, &efuse->efuse_rd.blk1[0], sizeof(s->efuse_key)); +} + +static void esp32_flash_encryption_init(Object *obj) +{ + Esp32FlashEncryptionState *s = ESP32_FLASH_ENCRYPTION(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_flash_encryption_ops, s, + TYPE_ESP32_FLASH_ENCRYPTION, + A_FLASH_ENCRYPTION_DONE + 4); + + qdev_init_gpio_in_named(DEVICE(s), esp32_flash_encryption_on_dl_mode_change, + ESP32_FLASH_ENCRYPTION_DL_MODE_GPIO, 1); + qdev_init_gpio_in_named(DEVICE(s), + esp32_flash_encryption_on_enc_enable_change, + ESP32_FLASH_ENCRYPTION_ENC_EN_GPIO, 1); + qdev_init_gpio_in_named(DEVICE(s), + esp32_flash_encryption_on_dec_enable_change, + ESP32_FLASH_ENCRYPTION_DEC_EN_GPIO, 1); + qdev_init_gpio_in_named(DEVICE(s), esp32_flash_encryption_on_efuse_update, + ESP32_FLASH_ENCRYPTION_EFUSE_UPDATE_GPIO, 1); + + sysbus_init_mmio(sbd, &s->iomem); +} + +static void esp32_flash_encryption_reset(DeviceState *dev) +{ + Esp32FlashEncryptionState *s = ESP32_FLASH_ENCRYPTION(dev); + s->encryption_done = false; +} + +static void esp32_flash_encryption_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32_flash_encryption_reset; +} + +static const TypeInfo esp32_flash_encryption_info = { + .name = TYPE_ESP32_FLASH_ENCRYPTION, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32FlashEncryptionState), + .instance_init = esp32_flash_encryption_init, + .class_init = esp32_flash_encryption_class_init +}; + +static void esp32_flash_encryption_register_types(void) +{ + type_register_static(&esp32_flash_encryption_info); +} + +type_init(esp32_flash_encryption_register_types) diff --git a/hw/misc/esp32_ledc.c b/hw/misc/esp32_ledc.c new file mode 100644 index 000000000000..9cebea98214e --- /dev/null +++ b/hw/misc/esp32_ledc.c @@ -0,0 +1,154 @@ +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "hw/misc/esp32_ledc.h" + +#define ESP32_LEDC_REGS_SIZE (A_LEDC_CONF_REG + 4) + +static uint64_t esp32_ledc_read(void *opaque, hwaddr addr, unsigned int size) +{ + Esp32LEDCState *s = ESP32_LEDC(opaque); + uint64_t r = 0; + switch (addr) { + case A_LEDC_HSTIMER0_CONF_REG ... A_LEDC_LSTIMER3_CONF_REG: + r = s->timer_conf_reg[(addr - A_LEDC_HSTIMER0_CONF_REG) / 0x8]; + break; + + case A_LEDC_HSCH0_CONF0_REG: + case A_LEDC_HSCH1_CONF0_REG: + case A_LEDC_HSCH2_CONF0_REG: + case A_LEDC_HSCH3_CONF0_REG: + case A_LEDC_HSCH4_CONF0_REG: + case A_LEDC_HSCH5_CONF0_REG: + case A_LEDC_HSCH6_CONF0_REG: + case A_LEDC_HSCH7_CONF0_REG: + case A_LEDC_LSCH0_CONF0_REG: + case A_LEDC_LSCH1_CONF0_REG: + case A_LEDC_LSCH2_CONF0_REG: + case A_LEDC_LSCH3_CONF0_REG: + case A_LEDC_LSCH4_CONF0_REG: + case A_LEDC_LSCH5_CONF0_REG: + case A_LEDC_LSCH6_CONF0_REG: + case A_LEDC_LSCH7_CONF0_REG: + r = s->channel_conf0_reg[(addr - A_LEDC_HSCH0_CONF0_REG) / 0x14]; + break; + } + return r; +} + +static uint32_t esp32_ledc_get_percent(Esp32LEDCState *s, uint32_t value, hwaddr addr) +{ + uint32_t duty_val = (value >> 4) & ((1 << 20) - 1); + uint32_t duty_res; + if (((addr - A_LEDC_HSCH0_DUTY_REG) / 0x14) < 8) { + /* get duty res for the high speed channel from high speed timer */ + duty_res = s->duty_res[(s->channel_conf0_reg[(addr - A_LEDC_HSCH0_DUTY_REG) / 0x14] & ((1 << 2) - 1))]; + } else { + /* get duty res for the low speed channel from low speed timer */ + duty_res = s->duty_res[((s->channel_conf0_reg[(addr - A_LEDC_HSCH0_DUTY_REG) / 0x14]) & ((1 << 2) - 1)) + 4]; + } + return duty_res ? (100 * duty_val / ((2 << (duty_res - 1)) - 1)) : 0; +} + +static void esp32_ledc_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + Esp32LEDCState *s = ESP32_LEDC(opaque); + switch (addr) { + case A_LEDC_HSTIMER0_CONF_REG ... A_LEDC_LSTIMER3_CONF_REG: + /* get duty resolution from timer config */ + if (((uint32_t)value & ((1 << 4) - 1)) != 0) { + s->duty_res[(addr - A_LEDC_HSTIMER0_CONF_REG) / 0x8] = (uint32_t)value & ((1 << 4) - 1); + } + s->timer_conf_reg[(addr - A_LEDC_HSTIMER0_CONF_REG) / 0x8] = value; + break; + + case A_LEDC_HSCH0_CONF0_REG: + case A_LEDC_HSCH1_CONF0_REG: + case A_LEDC_HSCH2_CONF0_REG: + case A_LEDC_HSCH3_CONF0_REG: + case A_LEDC_HSCH4_CONF0_REG: + case A_LEDC_HSCH5_CONF0_REG: + case A_LEDC_HSCH6_CONF0_REG: + case A_LEDC_HSCH7_CONF0_REG: + case A_LEDC_LSCH0_CONF0_REG: + case A_LEDC_LSCH1_CONF0_REG: + case A_LEDC_LSCH2_CONF0_REG: + case A_LEDC_LSCH3_CONF0_REG: + case A_LEDC_LSCH4_CONF0_REG: + case A_LEDC_LSCH5_CONF0_REG: + case A_LEDC_LSCH6_CONF0_REG: + case A_LEDC_LSCH7_CONF0_REG: + s->channel_conf0_reg[(addr - A_LEDC_HSCH0_CONF0_REG) / 0x14] = value; + break; + + case A_LEDC_HSCH0_DUTY_REG: + case A_LEDC_HSCH1_DUTY_REG: + case A_LEDC_HSCH2_DUTY_REG: + case A_LEDC_HSCH3_DUTY_REG: + case A_LEDC_HSCH4_DUTY_REG: + case A_LEDC_HSCH5_DUTY_REG: + case A_LEDC_HSCH6_DUTY_REG: + case A_LEDC_HSCH7_DUTY_REG: + case A_LEDC_LSCH0_DUTY_REG: + case A_LEDC_LSCH1_DUTY_REG: + case A_LEDC_LSCH2_DUTY_REG: + case A_LEDC_LSCH3_DUTY_REG: + case A_LEDC_LSCH4_DUTY_REG: + case A_LEDC_LSCH5_DUTY_REG: + case A_LEDC_LSCH6_DUTY_REG: + case A_LEDC_LSCH7_DUTY_REG: + led_set_intensity(&s->led[(addr - A_LEDC_HSCH0_DUTY_REG) / 0x14], esp32_ledc_get_percent(s, value, addr)); + break; + } + +} + +static const MemoryRegionOps esp32_ledc_ops = { + .read = esp32_ledc_read, + .write = esp32_ledc_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_ledc_realize(DeviceState *dev, Error **errp) +{ + Esp32LEDCState *s = ESP32_LEDC(dev); + for (int i = 0; i < ESP32_LEDC_CHANNEL_CNT; i++) { + qdev_realize(DEVICE(&s->led[i]), NULL, &error_fatal); + } +} + +static void esp32_ledc_init(Object *obj) +{ + Esp32LEDCState *s = ESP32_LEDC(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + memory_region_init_io(&s->iomem, obj, &esp32_ledc_ops, s, + TYPE_ESP32_LEDC, ESP32_LEDC_REGS_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + for (int i = 0; i < ESP32_LEDC_CHANNEL_CNT; i++) { + object_initialize_child(obj, g_strdup_printf("led%d", i + 1), &s->led[i], TYPE_LED); + s->led[i].color = (char *)"blue"; + } +} + +static void esp32_ledc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->realize = esp32_ledc_realize; +} + +static const TypeInfo esp32_ledc_info = { + .name = TYPE_ESP32_LEDC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32LEDCState), + .instance_init = esp32_ledc_init, + .class_init = esp32_ledc_class_init +}; + +static void esp32_ledc_register_types(void) +{ + type_register_static(&esp32_ledc_info); +} + +type_init(esp32_ledc_register_types) diff --git a/hw/misc/esp32_phya.c b/hw/misc/esp32_phya.c new file mode 100644 index 000000000000..38956e597524 --- /dev/null +++ b/hw/misc/esp32_phya.c @@ -0,0 +1,54 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qemu/guest-random.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32_phya.h" + +static uint64_t esp32_phya_read(void *opaque, hwaddr addr, unsigned int size) +{ + uint32_t r = 0; + Esp32PhyaState *s = ESP32_PHYA(opaque); + r=s->mem[addr/4]; + return r; +} + +static void esp32_phya_write(void *opaque, hwaddr addr, uint64_t value, + unsigned int size) { + Esp32PhyaState *s = ESP32_PHYA(opaque); + s->mem[addr/4]=(uint32_t)value; +} + +static const MemoryRegionOps esp32_phya_ops = { + .read = esp32_phya_read, + .write = esp32_phya_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_phya_init(Object *obj) +{ + Esp32PhyaState *s = ESP32_PHYA(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_phya_ops, s, + TYPE_ESP32_PHYA, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + memset(s->mem,0,sizeof(s->mem)); +} + + +static const TypeInfo esp32_phya_info = { + .name = TYPE_ESP32_PHYA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32PhyaState), + .instance_init = esp32_phya_init, +}; + +static void esp32_phya_register_types(void) +{ + type_register_static(&esp32_phya_info); +} + +type_init(esp32_phya_register_types) diff --git a/hw/misc/esp32_rng.c b/hw/misc/esp32_rng.c new file mode 100644 index 000000000000..9df49de9a527 --- /dev/null +++ b/hw/misc/esp32_rng.c @@ -0,0 +1,56 @@ +/* + * ESP32 Random Number Generator peripheral + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qemu/guest-random.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32_rng.h" + + +static uint64_t esp32_rng_read(void *opaque, hwaddr addr, unsigned int size) +{ + uint32_t r = 0; + qemu_guest_getrandom_nofail(&r, sizeof(r)); + return r; +} + +static const MemoryRegionOps esp32_rng_ops = { + .read = esp32_rng_read, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_rng_init(Object *obj) +{ + Esp32RngState *s = ESP32_RNG(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_rng_ops, s, + TYPE_ESP32_RNG, sizeof(uint32_t)); + sysbus_init_mmio(sbd, &s->iomem); +} + + +static const TypeInfo esp32_rng_info = { + .name = TYPE_ESP32_RNG, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32RngState), + .instance_init = esp32_rng_init, +}; + +static void esp32_rng_register_types(void) +{ + type_register_static(&esp32_rng_info); +} + +type_init(esp32_rng_register_types) diff --git a/hw/misc/esp32_rsa.c b/hw/misc/esp32_rsa.c new file mode 100644 index 000000000000..a996833085a8 --- /dev/null +++ b/hw/misc/esp32_rsa.c @@ -0,0 +1,365 @@ +/* + * ESP32 RSA accelerator + * + * Copyright (c) 2020 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/boards.h" +#include "hw/misc/esp32_rsa.h" +#include + + +#define ESP32_RSA_REGS_SIZE (A_RSA_QUERY_CLEAN_REG + 4) + +static void copy_reversed(unsigned char* dest, size_t dst_size, const unsigned char* src, size_t src_size); +static bool mpi_block_to_gcrypt(const uint32_t* mem_block, size_t n_bytes, gcry_mpi_t *out); +static bool mpi_gcrypt_to_block(gcry_mpi_t in, uint32_t* mem_block); +static void esp32_rsa_exp_mod(Esp32RsaState *s); +static void esp32_rsa_mul_start(Esp32RsaState *s); +static void esp32_rsa_mul_op(Esp32RsaState *s); +static void esp32_rsa_mod_mul_op(Esp32RsaState *s); + + +/** + * Convert between libgcrypt big-endian representation and little-endian hardware, or vice versa. + * src_size should not exceed dst_size. The remaining part of dst is filled with 0. + */ +static void copy_reversed(unsigned char* dst, size_t dst_size, const unsigned char* src, size_t src_size) +{ + assert(src_size <= dst_size); + size_t i; + for (i = 0; i < src_size; ++i) { + dst[i] = src[src_size - i - 1]; + } + for (; i < dst_size; ++i) { + dst[i] = 0; + } +} + +/** + * Converts the little-endian memory block of the RSA peripheral to a new gcry_mpi_t object. + * The caller is responsible for freeing the returned object. + */ +static bool mpi_block_to_gcrypt(const uint32_t* mem_block, size_t n_bytes, gcry_mpi_t *out) +{ + size_t scanned; + const unsigned char* mem_u8 = (const unsigned char*) mem_block; + unsigned char temp_buffer[ESP32_RSA_MEM_BLK_SIZE] = {}; + copy_reversed(temp_buffer, n_bytes, mem_u8, n_bytes); + gcry_error_t err = gcry_mpi_scan(out, GCRYMPI_FMT_USG, temp_buffer, n_bytes, &scanned); + if (err) { + fprintf(stderr, "%s: gcry_mpi_scan failed with error: %s (%d)", __func__, gcry_strerror(err), err); + return false; + } + if (scanned != n_bytes) { + fprintf(stderr, "%s: gcry_mpi_scan scanned %zu, expected %zu", __func__, scanned, n_bytes); + return false; + } + return true; +} + +/** + * Copies an MPI from gcry_mpi_t object to the RSA peripheral memory block. + */ +static bool mpi_gcrypt_to_block(gcry_mpi_t in, uint32_t* mem_block) +{ + size_t written; + unsigned char* mem_u8 = (unsigned char*) mem_block; + unsigned char temp_buffer[ESP32_RSA_MEM_BLK_SIZE] = {}; + gcry_error_t err = gcry_mpi_print(GCRYMPI_FMT_USG, temp_buffer, ESP32_RSA_MEM_BLK_SIZE, &written, in); + if (err) { + fprintf(stderr, "%s: gcry_mpi_print failed with error: %s (%d)", __func__, gcry_strerror(err), err); + return false; + } + copy_reversed(mem_u8, ESP32_RSA_MEM_BLK_SIZE, temp_buffer, written); + return true; +} + +/** Calculates Z_MEM = X_MEM ^ Y_MEM mod M_MEM. + * Unlike the real hardware, doesn't use the mprime register. + */ +static void esp32_rsa_exp_mod(Esp32RsaState *s) +{ + gcry_mpi_t x, y, z, m; + + size_t n_bytes = (s->rsa_modexp_mode_reg + 1) * 64; + + /* convert inputs to gcry_mpi_t */ + if (!mpi_block_to_gcrypt(s->rsa_x_mem, n_bytes, &x) || + !mpi_block_to_gcrypt(s->rsa_y_mem, n_bytes, &y) || + !mpi_block_to_gcrypt(s->rsa_m_mem, n_bytes, &m)) { + return; + } + + /* calculate the result and write it back */ + z = gcry_mpi_new(n_bytes); + gcry_mpi_powm(z, x, y, m); + mpi_gcrypt_to_block(z, s->rsa_z_mem); + + /* clean up */ + gcry_mpi_release(x); + gcry_mpi_release(y); + gcry_mpi_release(z); + gcry_mpi_release(m); + + /* indicate that the operation is complete */ + s->rsa_q_int_reg = 1; +} + + +static void esp32_rsa_mul_start(Esp32RsaState *s) +{ + /* Hardware does different operations depending on rsa_mult_mode_reg value: */ + bool is_mod_mult = (s->rsa_mult_mode_reg < 8); + if (is_mod_mult) { + esp32_rsa_mod_mul_op(s); + } else { + esp32_rsa_mul_op(s); + } +} + +/** Calculates Z_MEM = X_MEM * (Z_MEM >> n) */ +static void esp32_rsa_mul_op(Esp32RsaState *s) +{ + assert(s->rsa_mult_mode_reg >= 8 && s->rsa_mult_mode_reg < 16); + /* In this mode, the output length is set by rsa_mult_mode_reg, + * and the length of inputs is half of that. + * Z input is shifted (multiplied by 2^(input length in bits)), + * and needs to be shifted back before passing to gcry_mpi_mul. + */ + size_t n_bytes = (s->rsa_mult_mode_reg - 8 + 1) * 64; + size_t n_bytes_input = n_bytes / 2; + memcpy(s->rsa_z_mem, s->rsa_z_mem + n_bytes_input / sizeof(s->rsa_z_mem[0]), n_bytes_input); + memset(s->rsa_z_mem + n_bytes_input / sizeof(s->rsa_z_mem[0]), 0, n_bytes_input); + /* convert inputs to gcry_mpi_t */ + gcry_mpi_t x, z, result; + if (!mpi_block_to_gcrypt(s->rsa_x_mem, n_bytes, &x) || + !mpi_block_to_gcrypt(s->rsa_z_mem, n_bytes, &z)) { + return; + } + /* multiply */ + result = gcry_mpi_new(n_bytes * 8); + gcry_mpi_mul(result, x, z); + mpi_gcrypt_to_block(result, s->rsa_z_mem); + + /* clean up */ + gcry_mpi_release(x); + gcry_mpi_release(z); + gcry_mpi_release(result); + + /* indicate that the operation is complete */ + s->rsa_q_int_reg = 1; +} + +/** Calculates Z_MEM = Z_MEM * X_MEM * R^-1 mod M_MEM. + * + * Real hardware does this using Montgomery multiplication + * algorithm. Here we simply call the modular multiplication function + * twice. + * R^-1 is re-calculated if M_MEM is modified. + * M' (mprime) register value is ignored in this simulation. + */ +static void esp32_rsa_mod_mul_op(Esp32RsaState *s) +{ + assert(s->rsa_mult_mode_reg < 8); + /* In this mode, the output and input lengths are the same */ + size_t n_bytes = (s->rsa_mult_mode_reg + 1) * 64; + gcry_mpi_t m; + if (!mpi_block_to_gcrypt(s->rsa_m_mem, n_bytes, &m)) { + return; + } + /* Calculate R^-1 if it hasn't been calculated yet */ + if (!s->cache.valid) { + if (!s->cache.rinv) { + s->cache.rinv = gcry_mpi_new(n_bytes * 8); + } + gcry_mpi_t r = gcry_mpi_new(n_bytes * 8 + 1); + gcry_mpi_set_bit(r, n_bytes * 8); + if (!gcry_mpi_invm(s->cache.rinv, r, m)) { + qemu_log("%s: failed to calculate modulo inverse\n", __func__); + return; + } + s->cache.valid = true; + } + + /* convert inputs to gcry_mpi_t */ + gcry_mpi_t x, z, res1, res2; + if (!mpi_block_to_gcrypt(s->rsa_x_mem, n_bytes, &x) || + !mpi_block_to_gcrypt(s->rsa_z_mem, n_bytes, &z)) { + gcry_mpi_release(m); + return; + } + + /* temporaries */ + res1 = gcry_mpi_new(n_bytes * 8 * 2); + res2 = gcry_mpi_new(n_bytes * 8 * 2); + + /* res1 = X * Z mod M */ + gcry_mpi_mulm(res1, x, z, m); + /* res2 = X * Z * Rinv mod M */ + gcry_mpi_mulm(res2, res1, s->cache.rinv, m); + + /* write back */ + mpi_gcrypt_to_block(res2, s->rsa_z_mem); + + /* clean up */ + gcry_mpi_release(x); + gcry_mpi_release(z); + gcry_mpi_release(res1); + + /* indicate that the operation is complete */ + s->rsa_q_int_reg = 1; +} + + +static void esp32_rsa_clean_mem(Esp32RsaState *s) +{ + memset(s->rsa_m_mem, 0, sizeof(s->rsa_m_mem)); + memset(s->rsa_x_mem, 0, sizeof(s->rsa_x_mem)); + memset(s->rsa_y_mem, 0, sizeof(s->rsa_y_mem)); + memset(s->rsa_z_mem, 0, sizeof(s->rsa_z_mem)); + s->cache.valid = false; +} + +static uint64_t esp32_rsa_read(void *opaque, hwaddr addr, unsigned int size) +{ + Esp32RsaState *s = ESP32_RSA(opaque); + uint64_t val = 0; + + switch (addr) { + case A_RSA_MEM_Z_BLOCK_BASE ... (A_RSA_MEM_Z_BLOCK_BASE + ESP32_RSA_MEM_BLK_SIZE - 1): + val = s->rsa_z_mem[(addr - A_RSA_MEM_Z_BLOCK_BASE) / sizeof(uint32_t)]; + break; + + case A_RSA_QUERY_CLEAN_REG: + /* After coming out from reset, RSA Accelerator first initialize + * internal memory block to zeros before turning this register to 1. + * Software poll this register to read 1, before using the internal + * memory blocks. Internal memory block initialisation performed + * here before returning this read operation to 1. + */ + esp32_rsa_clean_mem(s); + val = s->rsa_clean_reg; + break; + + case A_RSA_QUERY_INTERRUPT_REG: + val = s->rsa_q_int_reg; + break; + } + + return val; +} + + +static void esp32_rsa_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + Esp32RsaState *s = ESP32_RSA(opaque); + + switch (addr) { + + case A_RSA_MEM_M_BLOCK_BASE ... (A_RSA_MEM_M_BLOCK_BASE + ESP32_RSA_MEM_BLK_SIZE - 1): + s->rsa_m_mem[(addr - A_RSA_MEM_M_BLOCK_BASE) / sizeof(uint32_t)] = (uint32_t)value; + s->cache.valid = false; + break; + + case A_RSA_MEM_RB_BLOCK_BASE ... (A_RSA_MEM_RB_BLOCK_BASE + ESP32_RSA_MEM_BLK_SIZE - 1): + s->rsa_z_mem[(addr - A_RSA_MEM_RB_BLOCK_BASE) / sizeof(uint32_t)] = (uint32_t)value; + break; + + case A_RSA_MEM_Y_BLOCK_BASE ... (A_RSA_MEM_Y_BLOCK_BASE + ESP32_RSA_MEM_BLK_SIZE - 1): + s->rsa_y_mem[(addr - A_RSA_MEM_Y_BLOCK_BASE) / sizeof(uint32_t)] = (uint32_t)value; + break; + + case A_RSA_MEM_X_BLOCK_BASE ... (A_RSA_MEM_X_BLOCK_BASE + ESP32_RSA_MEM_BLK_SIZE - 1): + s->rsa_x_mem[(addr - A_RSA_MEM_X_BLOCK_BASE) / sizeof(uint32_t)] = (uint32_t)value; + break; + + case A_RSA_M_DASH_REG: + s->rsa_mprime_reg = value; + break; + + case A_RSA_MODEXP_MODE_REG: + s->rsa_modexp_mode_reg = value; + break; + + case A_RSA_MULT_MODE_REG: + s->rsa_mult_mode_reg = value; + break; + + case A_RSA_MODEXP_START_REG: + esp32_rsa_exp_mod(s); + break; + + case A_RSA_MULT_START_REG: + esp32_rsa_mul_start(s); + break; + + case A_RSA_QUERY_INTERRUPT_REG: + /* Clear on write register */ + s->rsa_q_int_reg &= ~value; + break; + } + +} + +static const MemoryRegionOps esp32_rsa_ops = { + .read = esp32_rsa_read, + .write = esp32_rsa_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_rsa_reset(DeviceState *dev) +{ + Esp32RsaState *s = ESP32_RSA(dev); + + esp32_rsa_clean_mem(s); + + /* Clear any spurious interrupt */ + s->rsa_q_int_reg = 0; + + /* RSA memory block initialization complete */ + s->rsa_clean_reg = 1; +} + +static void esp32_rsa_init(Object *obj) +{ + Esp32RsaState *s = ESP32_RSA(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_rsa_ops, s, + TYPE_ESP32_RSA, ESP32_RSA_REGS_SIZE); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void esp32_rsa_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32_rsa_reset; +} + +static const TypeInfo esp32_rsa_info = { + .name = TYPE_ESP32_RSA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32RsaState), + .instance_init = esp32_rsa_init, + .class_init = esp32_rsa_class_init +}; + +static void esp32_rsa_register_types(void) +{ + type_register_static(&esp32_rsa_info); +} + +type_init(esp32_rsa_register_types) diff --git a/hw/misc/esp32_rtc_cntl.c b/hw/misc/esp32_rtc_cntl.c new file mode 100644 index 000000000000..f4087a126112 --- /dev/null +++ b/hw/misc/esp32_rtc_cntl.c @@ -0,0 +1,244 @@ +/* + * ESP32 RTC_CNTL (RTC block controller) device + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/misc/esp32_reg.h" +#include "hw/misc/esp32_rtc_cntl.h" + +static void esp32_rtc_update_cpu_stall(Esp32RtcCntlState* s); +static void esp32_rtc_update_clk(Esp32RtcCntlState* s); + +static uint64_t esp32_rtc_cntl_read(void *opaque, hwaddr addr, unsigned int size) +{ + Esp32RtcCntlState *s = ESP32_RTC_CNTL(opaque); + uint64_t r = 0; + switch (addr) { + case A_RTC_CNTL_OPTIONS0: + r = s->options0_reg; + break; + case A_RTC_CNTL_TIME_UPDATE: + r = R_RTC_CNTL_TIME_UPDATE_VALID_MASK; + break; + case A_RTC_CNTL_TIME0: + r = s->time_reg & UINT32_MAX; + break; + case A_RTC_CNTL_TIME1: + r = s->time_reg >> 32; + break; + + case A_RTC_CNTL_RESET_STATE: + r = FIELD_DP32(r, RTC_CNTL_RESET_STATE, RESET_CAUSE_PROCPU, s->reset_cause[0]); + r = FIELD_DP32(r, RTC_CNTL_RESET_STATE, RESET_CAUSE_APPCPU, s->reset_cause[1]); + r = FIELD_DP32(r, RTC_CNTL_RESET_STATE, PROCPU_STAT_VECTOR_SEL, s->stat_vector_sel[0]); + r = FIELD_DP32(r, RTC_CNTL_RESET_STATE, APPCPU_STAT_VECTOR_SEL, s->stat_vector_sel[1]); + break; + + case A_RTC_CNTL_STORE0: + case A_RTC_CNTL_STORE1: + case A_RTC_CNTL_STORE2: + case A_RTC_CNTL_STORE3: + r = s->scratch_reg[(addr - A_RTC_CNTL_STORE0) / 4]; + break; + + case A_RTC_CNTL_CLK_CONF: + r = FIELD_DP32(r, RTC_CNTL_CLK_CONF, SOC_CLK_SEL, s->soc_clk); + r = FIELD_DP32(r, RTC_CNTL_CLK_CONF, FAST_CLK_RTC_SEL, s->rtc_fastclk); + r = FIELD_DP32(r, RTC_CNTL_CLK_CONF, ANA_CLK_RTC_SEL, s->rtc_slowclk); + break; + + case A_RTC_CNTL_SW_CPU_STALL: + r = s->sw_cpu_stall_reg; + break; + + case A_RTC_CNTL_STORE4: + case A_RTC_CNTL_STORE5: + case A_RTC_CNTL_STORE6: + case A_RTC_CNTL_STORE7: + r = s->scratch_reg[(addr - A_RTC_CNTL_STORE4) / 4 + 4]; + break; + } + return r; +} + +static void esp32_rtc_cntl_write(void *opaque, hwaddr addr, uint64_t value, + unsigned int size) +{ + Esp32RtcCntlState *s = ESP32_RTC_CNTL(opaque); + switch (addr) { + case A_RTC_CNTL_OPTIONS0: + if (value & R_RTC_CNTL_OPTIONS0_SW_SYS_RESET_MASK) { + s->reset_cause[0] = ESP32_SW_SYS_RESET; + s->reset_cause[1] = ESP32_SW_SYS_RESET; + qemu_irq_pulse(s->dig_reset_req); + value &= ~(R_RTC_CNTL_OPTIONS0_SW_SYS_RESET_MASK); + } + if (value & R_RTC_CNTL_OPTIONS0_SW_APPCPU_RESET_MASK) { + s->reset_cause[1] = ESP32_SW_CPU_RESET; + qemu_irq_pulse(s->cpu_reset_req[1]); + value &= ~(R_RTC_CNTL_OPTIONS0_SW_APPCPU_RESET_MASK); + } + if (value & R_RTC_CNTL_OPTIONS0_SW_PROCPU_RESET_MASK) { + s->reset_cause[0] = ESP32_SW_CPU_RESET; + qemu_irq_pulse(s->cpu_reset_req[0]); + value &= ~(R_RTC_CNTL_OPTIONS0_SW_PROCPU_RESET_MASK); + } + s->options0_reg = value; + esp32_rtc_update_cpu_stall(s); + break; + + case A_RTC_CNTL_TIME_UPDATE: + if (value & R_RTC_CNTL_TIME_UPDATE_UPDATE_MASK) { + s->time_reg = muldiv64( + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->time_base_ns, + s->rtc_slowclk_freq, NANOSECONDS_PER_SECOND); + } + break; + + case A_RTC_CNTL_RESET_STATE: + s->stat_vector_sel[0] = FIELD_EX32(value, RTC_CNTL_RESET_STATE, + PROCPU_STAT_VECTOR_SEL); + s->stat_vector_sel[1] = FIELD_EX32(value, RTC_CNTL_RESET_STATE, + APPCPU_STAT_VECTOR_SEL); + break; + + case A_RTC_CNTL_STORE0: + case A_RTC_CNTL_STORE1: + case A_RTC_CNTL_STORE2: + case A_RTC_CNTL_STORE3: + s->scratch_reg[(addr - A_RTC_CNTL_STORE0) / 4] = value; + break; + + case A_RTC_CNTL_CLK_CONF: + s->soc_clk = FIELD_EX32(value, RTC_CNTL_CLK_CONF, SOC_CLK_SEL); + s->rtc_fastclk = FIELD_EX32(value, RTC_CNTL_CLK_CONF, FAST_CLK_RTC_SEL); + s->rtc_slowclk = FIELD_EX32(value, RTC_CNTL_CLK_CONF, ANA_CLK_RTC_SEL); + esp32_rtc_update_clk(s); + break; + + case A_RTC_CNTL_SW_CPU_STALL: + s->sw_cpu_stall_reg = value; + esp32_rtc_update_cpu_stall(s); + break; + + case A_RTC_CNTL_STORE4: + case A_RTC_CNTL_STORE5: + case A_RTC_CNTL_STORE6: + case A_RTC_CNTL_STORE7: + s->scratch_reg[(addr - A_RTC_CNTL_STORE4) / 4 + 4] = value; + break; + } +} + +static void esp32_rtc_update_cpu_stall(Esp32RtcCntlState* s) +{ + uint32_t procpu_stall = (FIELD_EX32(s->sw_cpu_stall_reg, RTC_CNTL_SW_CPU_STALL, PROCPU_C1) << 2) | + (FIELD_EX32(s->options0_reg, RTC_CNTL_OPTIONS0, SW_STALL_PROCPU_C0)); + + uint32_t appcpu_stall = (FIELD_EX32(s->sw_cpu_stall_reg, RTC_CNTL_SW_CPU_STALL, APPCPU_C1) << 2) | + (FIELD_EX32(s->options0_reg, RTC_CNTL_OPTIONS0, SW_STALL_APPCPU_C0)); + + const uint32_t stall_magic_val = 0x86; + + s->cpu_stall_state[0] = procpu_stall == stall_magic_val; + s->cpu_stall_state[1] = appcpu_stall == stall_magic_val; + + qemu_set_irq(s->cpu_stall_req[0], s->cpu_stall_state[0]); + qemu_set_irq(s->cpu_stall_req[1], s->cpu_stall_state[1]); +} + +static void esp32_rtc_update_clk(Esp32RtcCntlState* s) +{ + const uint32_t slowclk_freq[] = {150000, 32768, 8000000/256}; + const uint32_t fastclk_freq[] = {s->xtal_apb_freq / 4, 8000000}; + s->rtc_slowclk_freq = slowclk_freq[s->rtc_slowclk]; + s->rtc_fastclk_freq = fastclk_freq[s->rtc_fastclk]; + qemu_irq_pulse(s->clk_update); +} + +static const MemoryRegionOps esp32_rtc_cntl_ops = { + .read = esp32_rtc_cntl_read, + .write = esp32_rtc_cntl_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_rtc_cntl_reset(DeviceState *dev) +{ + Esp32RtcCntlState *s = ESP32_RTC_CNTL(dev); + + s->time_base_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +} + +static void esp32_rtc_cntl_realize(DeviceState *dev, Error **errp) +{ +} + +static void esp32_rtc_cntl_init(Object *obj) +{ + Esp32RtcCntlState *s = ESP32_RTC_CNTL(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_rtc_cntl_ops, s, + TYPE_ESP32_RTC_CNTL, ESP32_RTC_CNTL_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + qdev_init_gpio_out_named(DEVICE(sbd), &s->dig_reset_req, ESP32_RTC_DIG_RESET_GPIO, 1); + qdev_init_gpio_out_named(DEVICE(sbd), &s->cpu_reset_req[0], ESP32_RTC_CPU_RESET_GPIO, ESP32_CPU_COUNT); + qdev_init_gpio_out_named(DEVICE(sbd), &s->cpu_stall_req[0], ESP32_RTC_CPU_STALL_GPIO, ESP32_CPU_COUNT); + qdev_init_gpio_out_named(DEVICE(sbd), &s->clk_update, ESP32_RTC_CLK_UPDATE_GPIO, 1); + + for (int i = 0; i < ESP32_CPU_COUNT; ++i) { + s->reset_cause[i] = ESP32_POWERON_RESET; + s->stat_vector_sel[i] = true; + } + + s->rtc_slowclk = ESP32_SLOW_CLK_RC; + s->rtc_fastclk = ESP32_FAST_CLK_8M; + s->soc_clk = ESP32_SOC_CLK_XTAL; + s->xtal_apb_freq = 40000000; + s->pll_apb_freq = 80000000; + esp32_rtc_update_clk(s); +} + +static Property esp32_rtc_cntl_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32_rtc_cntl_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32_rtc_cntl_reset; + dc->realize = esp32_rtc_cntl_realize; + device_class_set_props(dc, esp32_rtc_cntl_properties); +} + +static const TypeInfo esp32_rtc_cntl_info = { + .name = TYPE_ESP32_RTC_CNTL, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32RtcCntlState), + .instance_init = esp32_rtc_cntl_init, + .class_init = esp32_rtc_cntl_class_init +}; + +static void esp32_rtc_cntl_register_types(void) +{ + type_register_static(&esp32_rtc_cntl_info); +} + +type_init(esp32_rtc_cntl_register_types) diff --git a/hw/misc/esp32_sha.c b/hw/misc/esp32_sha.c new file mode 100644 index 000000000000..411fb69d861c --- /dev/null +++ b/hw/misc/esp32_sha.c @@ -0,0 +1,132 @@ +/* + * ESP32 SHA accelerator + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "crypto/hash.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/boards.h" +#include "hw/misc/esp32_sha.h" + +#define ESP32_SHA_REGS_SIZE (A_SHA512_BUSY + 4) + +static void esp32_sha_text_reg_byteswap_to(Esp32ShaState* s, uint32_t* dst, size_t len_words) +{ + for (int i = 0; i < len_words; ++i) { + dst[i] = __builtin_bswap32(s->text[i]); + } +} + +static uint64_t esp32_sha_read(void *opaque, hwaddr addr, unsigned int size) +{ + Esp32ShaState *s = ESP32_SHA(opaque); + uint64_t r = 0; + switch (addr) { + case 0 ... (ESP32_SHA_TEXT_REG_CNT - 1) * sizeof(uint32_t): + r = s->text[addr / sizeof(uint32_t)]; + break; + } + return r; +} + +static void esp32_sha_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + Esp32ShaState *s = ESP32_SHA(opaque); + switch (addr) { + case 0 ... (ESP32_SHA_TEXT_REG_CNT - 1) * sizeof(uint32_t): + s->text[addr / sizeof(uint32_t)] = value; + break; + case A_SHA1_START: + sha1_init(&s->sha1); + esp32_sha_text_reg_byteswap_to(s, (uint32_t *) s->text, 16); + sha1_compress((uint32_t *)&s->sha1.state, (unsigned char *)s->text); + break; + case A_SHA256_START: + sha256_init(&s->sha256); + esp32_sha_text_reg_byteswap_to(s, (uint32_t *) s->text, 16); + sha256_compress(&s->sha256, (unsigned char *)s->text); + break; + case A_SHA384_START: + sha384_init(&s->sha512); + esp32_sha_text_reg_byteswap_to(s, (uint32_t *) s->text, 32); + sha512_compress(&s->sha512, (unsigned char *)s->text); + break; + case A_SHA512_START: + sha512_init(&s->sha512); + esp32_sha_text_reg_byteswap_to(s, (uint32_t *) s->text, 32); + sha512_compress(&s->sha512, (unsigned char *)s->text); + break; + case A_SHA1_CONTINUE: + esp32_sha_text_reg_byteswap_to(s, (uint32_t *) s->text, 16); + sha1_compress((uint32_t *)&s->sha1.state, (unsigned char *)s->text); + break; + case A_SHA256_CONTINUE: + esp32_sha_text_reg_byteswap_to(s, (uint32_t *) s->text, 16); + sha256_compress(&s->sha256, (unsigned char *)s->text); + break; + case A_SHA384_CONTINUE: + case A_SHA512_CONTINUE: + esp32_sha_text_reg_byteswap_to(s, (uint32_t *) s->text, 32); + sha512_compress(&s->sha512, (unsigned char *)s->text); + break; + case A_SHA1_LOAD: + for (int i = 0; i < 5; i++) { + s->text[i] = s->sha1.state[i]; + } + break; + case A_SHA256_LOAD: + for (int i = 0; i < 8; i++) { + s->text[i] = s->sha256.state[i]; + } + break; + case A_SHA384_LOAD: + case A_SHA512_LOAD: + for (int i = 0; i < 8; i++) { + s->text[i * 2] = (uint32_t)(s->sha512.state[i] >> 32); + s->text[1 + (i * 2)] = (uint32_t)(s->sha512.state[i] & 0xffffffff); + } + break; + } +} + +static const MemoryRegionOps esp32_sha_ops = { + .read = esp32_sha_read, + .write = esp32_sha_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_sha_init(Object *obj) +{ + Esp32ShaState *s = ESP32_SHA(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_sha_ops, s, + TYPE_ESP32_SHA, ESP32_SHA_REGS_SIZE); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const TypeInfo esp32_sha_info = { + .name = TYPE_ESP32_SHA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32ShaState), + .instance_init = esp32_sha_init, +}; + +static void esp32_sha_register_types(void) +{ + type_register_static(&esp32_sha_info); +} + +type_init(esp32_sha_register_types) diff --git a/hw/misc/esp32_unknown.c b/hw/misc/esp32_unknown.c new file mode 100644 index 000000000000..4ff39932a74d --- /dev/null +++ b/hw/misc/esp32_unknown.c @@ -0,0 +1,75 @@ +/* ESP32 unknown peripheral handler +*/ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/boards.h" +#include "hw/misc/esp32_unknown.h" +#include "hw/misc/esp32_reg.h" + +static uint64_t esp32_unknown_read(void *opaque, hwaddr addr, unsigned int size) +{ + addr += 0x3ff00000; + uint64_t r = 0; + switch (addr) { + case (DR_REG_ANA_BASE + 0x04c): { // used in ram_txdc_cal_v70, esp32.analog region + r = 0x1000000; + break; + } + case 0x3ff4607c: { // used in ram_iq_est_enable, reserved region + r = 0xffffffff; + break; + } + + default: { + printf("unknown read for %016lX\n", addr); + break; + } + } + // Esp32UnknownState *s = ESP32_UNKNOWN(opaque); + return r; +} + +static void esp32_unknown_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + addr += 0x3ff00000; + // Esp32UnknownState *s = ESP32_UNKNOWN(opaque); + printf("unknown write for %016lX, setting to %ld (size=%d)\n", addr, value, size); + +} + +static const MemoryRegionOps esp32_unknown_ops = { + .read = esp32_unknown_read, + .write = esp32_unknown_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_unknown_init(Object *obj) +{ + Esp32UnknownState *s = ESP32_UNKNOWN(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_unknown_ops, s, + TYPE_ESP32_UNKNOWN, 0x80000); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const TypeInfo esp32_unknown_info = { + .name = TYPE_ESP32_UNKNOWN, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32UnknownState), + .instance_init = esp32_unknown_init, +}; + +static void esp32_unknown_register_types(void) +{ + type_register_static(&esp32_unknown_info); +} + +type_init(esp32_unknown_register_types) diff --git a/hw/misc/esp32_wifi.c b/hw/misc/esp32_wifi.c new file mode 100644 index 000000000000..d723c7ee2ebe --- /dev/null +++ b/hw/misc/esp32_wifi.c @@ -0,0 +1,173 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qemu/guest-random.h" +#include "qapi/error.h" +#include "sysemu/sysemu.h" +#include "hw/hw.h" +#include "hw/irq.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32_wifi.h" +#include "exec/address-spaces.h" +#include "esp32_wlan_packet.h" +#include "hw/qdev-properties.h" + +#define DEBUG 0 + +static uint64_t esp32_wifi_read(void *opaque, hwaddr addr, unsigned int size) +{ + + Esp32WifiState *s = ESP32_WIFI(opaque); + uint32_t r = s->mem[addr/4]; + + switch(addr) { + case A_WIFI_DMA_IN_STATUS: + r=0; + break; + case A_WIFI_DMA_INT_STATUS: + case A_WIFI_DMA_INT_CLR: + r=s->raw_interrupt; + break; + case A_WIFI_STATUS: + case A_WIFI_DMA_OUT_STATUS: + r=1; + break; + } + + if(DEBUG) printf("esp32_wifi_read %lx=%x\n",addr,r); + + return r; +} +static void set_interrupt(Esp32WifiState *s, int e) { + s->raw_interrupt |= e; + qemu_set_irq(s->irq, 1); +} + +static void esp32_wifi_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size) { + Esp32WifiState *s = ESP32_WIFI(opaque); + if(DEBUG) printf("esp32_wifi_write %lx=%lx\n",addr, value); + + switch (addr) { + case A_WIFI_DMA_INLINK: + s->dma_inlink_address = value; + break; + case A_WIFI_DMA_INT_CLR: + s->raw_interrupt &= ~value; + if (s->raw_interrupt == 0) + qemu_set_irq(s->irq, 0); + break; + case A_WIFI_DMA_OUTLINK: + if (value & 0xc0000000) { + // do a DMA transfer to the hardware from esp32 memory + mac80211_frame frame; + dma_list_item item; + unsigned memaddr = (0x3ff00000 | (value & 0xfffff)); + address_space_read(&address_space_memory, memaddr, MEMTXATTRS_UNSPECIFIED, &item, 12); + address_space_read(&address_space_memory, item.address, MEMTXATTRS_UNSPECIFIED, &frame, item.length); + // frame from esp32 to ap + frame.frame_length=item.length; + frame.next_frame=0; + Esp32_WLAN_handle_frame(s, &frame); + set_interrupt(s, 0x80); + } + } + s->mem[addr/4]=value; +} + +static int match_mac_address(uint8_t *a1,uint8_t *a2) { + if(!memcmp(a1,a2,6)) return 1; + if(!memcmp(a1,BROADCAST,6)) return 1; + return 0; +} + +// frame from QEMU to ESP32 +void Esp32_sendFrame(Esp32WifiState *s, mac80211_frame *frame, int length, int signal_strength) { + + if(s->dma_inlink_address == 0) { + return; + } + uint8_t header[28+length]; + wifi_pkt_rx_ctrl_t *pkt=(wifi_pkt_rx_ctrl_t *)header; + *pkt=(wifi_pkt_rx_ctrl_t){ + .rssi=(signal_strength+(rand()%10)+96), + .rate=11, + .sig_len=length, + .sig_len_copy=length, + .legacy_length=length, + .noise_floor=-97, + .channel=esp32_wifi_channel, + .timestamp=qemu_clock_get_ns(QEMU_CLOCK_REALTIME)/1000, + }; + // These 4 bits are set if the mac addresses previously stored at 0x40 and 0x48 + // match the destination or bssid addresses in the frame + if(match_mac_address(frame->receiver_address,(uint8_t *)s->mem+0x40)) + pkt->damatch0=1; + if(match_mac_address(frame->receiver_address,(uint8_t *)s->mem+0x48)) + pkt->damatch1=1; + if(match_mac_address(frame->address_3,(uint8_t *)s->mem+0x40)) + pkt->bssidmatch0=1; + if(match_mac_address(frame->address_3,(uint8_t *)s->mem+0x48)) + pkt->bssidmatch1=1; + //printf("...%x %x\n",header[3],frame->receiver_address[0]); + + memcpy(header+28, frame, length); + length += 28; + // do a DMA transfer from the hardware to esp32 memory + dma_list_item item; + address_space_read(&address_space_memory, s->dma_inlink_address, MEMTXATTRS_UNSPECIFIED, &item, 12); + address_space_write(&address_space_memory, item.address, MEMTXATTRS_UNSPECIFIED, header, length); + item.length=length; + item.eof=1; + address_space_write(&address_space_memory, s->dma_inlink_address, MEMTXATTRS_UNSPECIFIED,&item,4); + s->dma_inlink_address=item.next; + set_interrupt(s, 0x1000024); +} + +static const MemoryRegionOps esp32_wifi_ops = { + .read = esp32_wifi_read, + .write = esp32_wifi_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_wifi_realize(DeviceState *dev, Error **errp) +{ + Esp32WifiState *s = ESP32_WIFI(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + s->dma_inlink_address = 0; + + memory_region_init_io(&s->iomem, OBJECT(dev), &esp32_wifi_ops, s, + TYPE_ESP32_WIFI, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + memset(s->mem,0,sizeof(s->mem)); + Esp32_WLAN_setup_ap(dev, s); + +} +static Property esp32_wifi_properties[] = { + DEFINE_NIC_PROPERTIES(Esp32WifiState, conf), + DEFINE_PROP_END_OF_LIST(), +}; +static void esp32_wifi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = esp32_wifi_realize; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); + dc->desc = "Esp32 WiFi"; + device_class_set_props(dc, esp32_wifi_properties); +} + + +static const TypeInfo esp32_wifi_info = { + .name = TYPE_ESP32_WIFI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32WifiState), + .class_init = esp32_wifi_class_init, +}; + +static void esp32_wifi_register_types(void) +{ + type_register_static(&esp32_wifi_info); +} + +type_init(esp32_wifi_register_types) diff --git a/hw/misc/esp32_wifi_ap.c b/hw/misc/esp32_wifi_ap.c new file mode 100644 index 000000000000..5892d82bd29c --- /dev/null +++ b/hw/misc/esp32_wifi_ap.c @@ -0,0 +1,410 @@ +/** + * QEMU WLAN access point emulation + * + * Copyright (c) 2008 Clemens Kolbitsch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Modifications: + * 2008-February-24 Clemens Kolbitsch : + * New implementation based on ne2000.c + * 18/1/22 Martin Johnson : Modified for esp32 wifi emulation + */ + +#include "qemu/osdep.h" +#include "net/net.h" +#include "qemu/timer.h" + +#include "hw/misc/esp32_wifi.h" +#include "esp32_wlan.h" +#include "esp32_wlan_packet.h" + +// 50ms between beacons +#define BEACON_TIME 50000000 +#define INTER_FRAME_TIME 5000000 +#define DEBUG 1 +#define DEBUG_DUMPFRAMES 1 + +// channel 12, 13 and 14 aren't scanned with probe requests, but by listening to beacons +// likely because those channels aren't freely licensed in all countries +access_point_info access_points[]={ + {"Open Wifi",4,-40,{0x10,0x01,0x00,0xc4,0x0a,0x51}}, + {"meshtest",1,-25,{0x10,0x01,0x00,0xc4,0x0a,0x50}}, + {"Zeus WPI",12,-25,{0x10,0x01,0x00,0xc4,0x0a,0x56}} +}; + +int nb_aps=sizeof(access_points)/sizeof(access_point_info); + +static void Esp32_WLAN_beacon_timer(void *opaque) +{ + struct mac80211_frame *frame; + Esp32WifiState *s = (Esp32WifiState *)opaque; + + // only send a beacon if we are an access point + if(s->ap_state!=Esp32_WLAN__STATE_STA_ASSOCIATED) { + if (access_points[s->beacon_ap].channel==esp32_wifi_channel) { + printf("QEMU: sending beacon for AP %s\n", access_points[s->beacon_ap].ssid); + memcpy(s->ap_macaddr,access_points[s->beacon_ap].mac_address,6); + frame = Esp32_WLAN_create_beacon_frame(&access_points[s->beacon_ap]); + memcpy(frame->receiver_address, BROADCAST, 6); + memcpy(frame->transmitter_address, s->ap_macaddr, 6); + memcpy(frame->address_3, s->ap_macaddr, 6); + Esp32_WLAN_init_ap_frame(s, frame); + Esp32_WLAN_insert_frame(s, frame); + } + s->beacon_ap=(s->beacon_ap+1)%nb_aps; + } + timer_mod(s->beacon_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + BEACON_TIME); +} + +static void Esp32_WLAN_inject_timer(void *opaque) +{ + Esp32WifiState *s = (Esp32WifiState *)opaque; + struct mac80211_frame *frame; + + frame = s->inject_queue; + if (frame) { + // remove from queue + s->inject_queue_size--; + s->inject_queue = frame->next_frame; + Esp32_sendFrame(s, (void *)frame, frame->frame_length,frame->signal_strength); + free(frame); + } + if (s->inject_queue_size > 0) { + // there are more packets... schedule + // the timer for sending them as well + timer_mod(s->inject_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + INTER_FRAME_TIME); + } else { + // we wait until a new packet schedules + // us again + s->inject_timer_running = 0; + } + +} + +static void macprint(uint8_t *p, const char * name) { + printf("%s: %02x:%02x:%02x:%02x:%02x:%02x\n",name, p[0],p[1],p[2],p[3],p[4],p[5]); +} + +static void infoprint(struct mac80211_frame *frame) { + if(DEBUG_DUMPFRAMES) { + printf("Frame Info type=%d subtype=%d to_ds=%d from_ds=%d duration=%d frame_length=%d\n",frame->frame_control.type,frame->frame_control.sub_type, frame->frame_control.to_ds,frame->frame_control.from_ds, frame->duration_id, frame->frame_length); + macprint(frame->receiver_address, "receiver "); + macprint(frame->transmitter_address,"transmitter"); + macprint(frame->address_3, "3rd address"); + uint8_t *b=(uint8_t *)frame; + for(int i=0;iframe_length;i++) { + if((i%16)==0) printf("\n%04x: ",i); + printf("%02x ",b[i]); + } + printf("\n"); + } +} + +void Esp32_WLAN_insert_frame(Esp32WifiState *s, struct mac80211_frame *frame) +{ + struct mac80211_frame *i_frame; + + insertCRC(frame); + if(DEBUG) printf("QEMU: sent frame (qemu AP -> ESP32) type=%d subtype=%d\n",frame->frame_control.type,frame->frame_control.sub_type); + infoprint(frame); + s->inject_queue_size++; + i_frame = s->inject_queue; + if (!i_frame) { + s->inject_queue = frame; + } else { + while (i_frame->next_frame) { + i_frame = i_frame->next_frame; + } + i_frame->next_frame = frame; + } + + if (!s->inject_timer_running) { + // if the injection timer is not + // running currently, let's schedule + // one run... + s->inject_timer_running = 1; + timer_mod(s->inject_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + INTER_FRAME_TIME); + } + +} + +static _Bool Esp32_WLAN_can_receive(NetClientState *ncs) +{ + Esp32WifiState *s = qemu_get_nic_opaque(ncs); + + if (s->ap_state != Esp32_WLAN__STATE_ASSOCIATED && s->ap_state != Esp32_WLAN__STATE_STA_ASSOCIATED) { + // we are currently not connected + // to the access point + return 0; + } + if (s->inject_queue_size > Esp32_WLAN__MAX_INJECT_QUEUE_SIZE) { + // overload, please give me some time... + return 0; + } + + return 1; +} + +static ssize_t Esp32_WLAN_receive(NetClientState *ncs, + const uint8_t *buf, size_t size) +{ + Esp32WifiState *s = qemu_get_nic_opaque(ncs); + struct mac80211_frame *frame; + if (!Esp32_WLAN_can_receive(ncs)) { + // this should not happen, but in + // case it does, let's simply drop + // the packet + return -1; + } + + if (!s) { + return -1; + } + /* + * A 802.3 packet comes from the qemu network. The + * access points turns it into a 802.11 frame and + * forwards it to the wireless device + */ + frame = Esp32_WLAN_create_data_packet(s, buf, size); + if (frame) { + /* send message to ESP32 AP */ + if(s->ap_state == Esp32_WLAN__STATE_STA_ASSOCIATED) { + printf("QEMU: Esp32_WLAN_create_data_packet not yet implemented for STA!"); + frame->frame_control.to_ds = 1; + frame->frame_control.from_ds = 0; + memcpy(frame->receiver_address, s->ap_macaddr, 6); // ? + // TODO implement setting all 3 802.11 MAC addresses + } + else { // send message to ESP32 station + frame->frame_control.to_ds = 0; + frame->frame_control.from_ds = 1; + memcpy(frame->receiver_address, &buf[0], 6); + memcpy(frame->transmitter_address, s->associated_ap_macaddr, 6); + memcpy(frame->address_3, &buf[6], 6); // source address + } + Esp32_WLAN_init_ap_frame(s, frame); + Esp32_WLAN_insert_frame(s, frame); + } + return size; +} +static void Esp32_WLAN_cleanup(NetClientState *ncs) { } + +static NetClientInfo net_info = { + .type = NET_CLIENT_DRIVER_NIC, + .size = sizeof(NICState), + .can_receive = Esp32_WLAN_can_receive, + .receive = Esp32_WLAN_receive, + .cleanup = Esp32_WLAN_cleanup, +}; + +void Esp32_WLAN_setup_ap(DeviceState *dev,Esp32WifiState *s) { + + s->ap_state = Esp32_WLAN__STATE_NOT_AUTHENTICATED; + s->beacon_ap=0; + memcpy(s->ap_macaddr,(uint8_t[]){0x01,0x13,0x46,0xbf,0x31,0x50},sizeof(s->ap_macaddr)); + memcpy(s->macaddr,(uint8_t[]){0x10,0x01,0x00,0xc4,0x0a,0x24},sizeof(s->macaddr)); + + s->inject_timer_running = 0; + s->inject_sequence_number = 0; + + s->inject_queue = NULL; + s->inject_queue_size = 0; + + s->beacon_timer = timer_new_ns(QEMU_CLOCK_REALTIME, Esp32_WLAN_beacon_timer, s); + timer_mod(s->beacon_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME)+100000000); + + // setup the timer but only schedule + // it when necessary... + s->inject_timer = timer_new_ns(QEMU_CLOCK_REALTIME, Esp32_WLAN_inject_timer, s); + + s->nic = qemu_new_nic(&net_info, &s->conf, object_get_typename(OBJECT(s)), dev->id, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->macaddr); +} + +static void send_single_frame(Esp32WifiState *s, struct mac80211_frame *frame, struct mac80211_frame *reply) { + reply->sequence_control.sequence_number = s->inject_sequence_number++ +0x730; + reply->signal_strength=-10; + + if(frame) { + memcpy(reply->receiver_address, frame->transmitter_address, 6); + memcpy(reply->transmitter_address, s->macaddr, 6); + memcpy(reply->address_3, frame->transmitter_address, 6); + } + + Esp32_WLAN_insert_frame(s, reply); +} +void Esp32_WLAN_handle_frame(Esp32WifiState *s, struct mac80211_frame *frame) +{ + struct mac80211_frame *reply = NULL; + static access_point_info dummy_ap={0}; + char ssid[64]; + unsigned long ethernet_frame_size; + unsigned char ethernet_frame[1518] = {0}; + if(DEBUG) + printf("QEMU: received frame (esp32 -> qemu) type=%d subtype=%d chan=%d to_ds=%d from_ds=%d state=%d\n",frame->frame_control.type, frame->frame_control.sub_type, esp32_wifi_channel, frame->frame_control.to_ds, frame->frame_control.from_ds, s->ap_state); + infoprint(frame); + access_point_info *ap_info=0; + for (int i=0;iframe_control.type == IEEE80211_TYPE_MGT) { + switch(frame->frame_control.sub_type) { + case IEEE80211_TYPE_MGT_SUBTYPE_BEACON: + if(s->ap_state==Esp32_WLAN__STATE_NOT_AUTHENTICATED || s->ap_state==Esp32_WLAN__STATE_AUTHENTICATED) { + strncpy(ssid,(char *)frame->data_and_fcs+14,frame->data_and_fcs[13]); + if(DEBUG) printf("QEMU: beacon from %s\n",ssid); + dummy_ap.ssid=ssid; + s->ap_state=Esp32_WLAN__STATE_STA_NOT_AUTHENTICATED; + send_single_frame(s,frame,Esp32_WLAN_create_probe_request(&dummy_ap)); + } + break; + case IEEE80211_TYPE_MGT_SUBTYPE_PROBE_RESP: + ap_info=&dummy_ap; + strncpy(ssid,(char *)frame->data_and_fcs+14,frame->data_and_fcs[13]); + if(DEBUG) printf("QEMU: probe resp from %s\n",ssid); + dummy_ap.ssid=ssid; + s->ap_state=Esp32_WLAN__STATE_STA_NOT_AUTHENTICATED; + send_single_frame(s,frame,Esp32_WLAN_create_deauthentication()); + send_single_frame(s,frame,Esp32_WLAN_create_authentication_request()); + break; + case IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_RESP: + if(DEBUG) printf("QEMU: assoc resp\n"); + mac80211_frame *frame1=Esp32_WLAN_create_dhcp_discover(); + memcpy(frame1->address_3,BROADCAST,6); + memcpy(frame1->transmitter_address,frame->receiver_address,6); + memcpy(frame1->receiver_address,frame->transmitter_address,6); + send_single_frame(s,0,frame1); + s->ap_state=Esp32_WLAN__STATE_STA_DHCP; + break; + case IEEE80211_TYPE_MGT_SUBTYPE_DISASSOCIATION: + DEBUG_PRINT_AP(("QEMU: Received disassociation!\n")); + send_single_frame(s,frame,Esp32_WLAN_create_disassociation()); + if (s->ap_state == Esp32_WLAN__STATE_ASSOCIATED || s->ap_state == Esp32_WLAN__STATE_STA_ASSOCIATED) { + s->ap_state = Esp32_WLAN__STATE_AUTHENTICATED; + } + break; + case IEEE80211_TYPE_MGT_SUBTYPE_DEAUTHENTICATION: + DEBUG_PRINT_AP(("QEMU: Received deauthentication!\n")); + //reply = Esp32_WLAN_create_authentication_response(ap_info); + if (s->ap_state == Esp32_WLAN__STATE_AUTHENTICATED) { + s->ap_state = Esp32_WLAN__STATE_NOT_AUTHENTICATED; + } + break; + case IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION: + if(frame->data_and_fcs[2]==2) { // response + DEBUG_PRINT_AP(("QEMU: Received authentication response!\n")); + send_single_frame(s,frame,Esp32_WLAN_create_association_request(&dummy_ap)); + } + break; + } + if(ap_info) { + memcpy(s->ap_macaddr, ap_info->mac_address, 6); + switch(frame->frame_control.sub_type) { + case IEEE80211_TYPE_MGT_SUBTYPE_PROBE_REQ: + DEBUG_PRINT_AP(("QEMU: Received probe request!\n")); + reply = Esp32_WLAN_create_probe_response(ap_info); + break; + case IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION: + if(frame->data_and_fcs[2]==1) { // request + DEBUG_PRINT_AP(("QEMU: Received authentication request!\n")); + reply = Esp32_WLAN_create_authentication_response(ap_info); + if (s->ap_state == Esp32_WLAN__STATE_NOT_AUTHENTICATED) { + s->ap_state = Esp32_WLAN__STATE_AUTHENTICATED; + } + } + break; + case IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_REQ: + DEBUG_PRINT_AP(("QEMU: Received association request!\n")); + reply = Esp32_WLAN_create_association_response(ap_info); + if (s->ap_state == Esp32_WLAN__STATE_AUTHENTICATED) { + s->ap_state = Esp32_WLAN__STATE_ASSOCIATED; + memcpy(s->associated_ap_macaddr,s->ap_macaddr,6); + } + break; + } + if (reply) { + reply->signal_strength=ap_info->sigstrength; + memcpy(reply->receiver_address, frame->transmitter_address, 6); + memcpy(reply->transmitter_address, s->ap_macaddr, 6); + memcpy(reply->address_3, s->ap_macaddr, 6); + Esp32_WLAN_init_ap_frame(s, reply); + Esp32_WLAN_insert_frame(s, reply); + } + } + } + if ((frame->frame_control.type == IEEE80211_TYPE_DATA) && + (frame->frame_control.sub_type == IEEE80211_TYPE_DATA_SUBTYPE_DATA)) { + if(s->ap_state == Esp32_WLAN__STATE_STA_DHCP) { + printf("QEMU: STA DHCP not implemented yet\n"); + dhcp_request_t *req=(dhcp_request_t *)&frame->data_and_fcs[8]; + // check for a dhcp offer + if(req->dhcp.bp_options[0]==0x35 && req->dhcp.bp_options[2]==0x2) { + mac80211_frame *frame1=Esp32_WLAN_create_dhcp_request(req->dhcp.yiaddr); + memcpy(frame1->address_3,BROADCAST,6); + memcpy(frame1->transmitter_address,s->macaddr,6); + memcpy(frame1->receiver_address,frame->transmitter_address,6); + send_single_frame(s,0,frame1); + memcpy(s->ap_macaddr,(uint8_t[]){0x10,0x01,0x00,0xc4,0x0a,0x25},sizeof(s->ap_macaddr)); + memcpy(s->macaddr,(uint8_t[]){0x10,0x01,0x00,0xc4,0x0a,0x24},sizeof(s->macaddr)); + memcpy(s->associated_ap_macaddr,s->ap_macaddr,sizeof(s->ap_macaddr)); + s->ap_state=Esp32_WLAN__STATE_STA_ASSOCIATED; + } + } else if (s->ap_state == Esp32_WLAN__STATE_ASSOCIATED) { + // ESP32 to QEMU + /* + * The access point uses the 802.11 frame + * and sends a 802.3 frame into the network... + * This packet is then understandable by + * qemu-slirp + * + * If we ever want the access point to offer + * some services, it can be added here!! + */ + // ethernet header type + ethernet_frame[12] = frame->data_and_fcs[6]; + ethernet_frame[13] = frame->data_and_fcs[7]; + + // the originator the packet is the station who sent the frame + memcpy(ðernet_frame[6], frame->transmitter_address, 6); + + // in case of to_ds = 1 and from_ds = 0, the third address is the destination address + memcpy(ðernet_frame[0], frame->address_3, 6); + + ethernet_frame_size = frame->frame_length - 22; + + // limit data to max length of ethernet frame + if (ethernet_frame_size > (sizeof(ethernet_frame) - 14)) { + ethernet_frame_size = (sizeof(ethernet_frame) - 14); + } + + // set ethernet data + memcpy(ðernet_frame[14], &frame->data_and_fcs[8], ethernet_frame_size); + + // send frame + qemu_send_packet(qemu_get_queue(s->nic), ethernet_frame, ethernet_frame_size); + } else if (s->ap_state == Esp32_WLAN__STATE_STA_ASSOCIATED) { + printf("QEMU: STA DATA, NOT IMPLEMENTED YET\n"); + } + } +} diff --git a/hw/misc/esp32_wlan.h b/hw/misc/esp32_wlan.h new file mode 100644 index 000000000000..ce55120912b0 --- /dev/null +++ b/hw/misc/esp32_wlan.h @@ -0,0 +1,226 @@ +/** + * QEMU WLAN device emulation + * + * Copyright (c) 2008 Clemens Kolbitsch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Modifications: + * 2008-February-24 Clemens Kolbitsch : + * New implementation based on ne2000.c + * 18/1/22 Martin Johnson : Modified for esp32 wifi emulation + * + */ + +#ifndef esp32_wlan_h +#define esp32_wlan_h 1 + + +#define DEBUG_Esp32_WLAN + +#ifdef DEBUG_Esp32_WLAN +#define DEBUG_PRINT_AP(x) \ + do { \ + struct timeval __tt; \ + gettimeofday(&__tt, NULL); \ + printf("%u:%u ", (unsigned)__tt.tv_sec, (unsigned)__tt.tv_usec); \ + printf x ;\ + } while (0) +#else +#define DEBUG_PRINT_AP(x) +#endif + + +#define IEEE80211_IDLE 0xff + +#define IEEE80211_TYPE_MGT 0x00 +#define IEEE80211_TYPE_CTL 0x01 +#define IEEE80211_TYPE_DATA 0x02 + +#define IEEE80211_TYPE_MGT_SUBTYPE_BEACON 0x08 +#define IEEE80211_TYPE_MGT_SUBTYPE_ACTION 0x0d +#define IEEE80211_TYPE_MGT_SUBTYPE_PROBE_REQ 0x04 +#define IEEE80211_TYPE_MGT_SUBTYPE_PROBE_RESP 0x05 +#define IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION 0x0b +#define IEEE80211_TYPE_MGT_SUBTYPE_DEAUTHENTICATION 0x0c +#define IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_REQ 0x00 +#define IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_RESP 0x01 +#define IEEE80211_TYPE_MGT_SUBTYPE_DISASSOCIATION 0x0a + +#define IEEE80211_TYPE_CTL_SUBTYPE_ACK 0x0d + +#define IEEE80211_TYPE_DATA_SUBTYPE_DATA 0x00 + +#define IEEE80211_BEACON_PARAM_SSID 0x00 +#define IEEE80211_BEACON_PARAM_RATES 0x01 +#define IEEE80211_BEACON_PARAM_CHANNEL 0x03 +#define IEEE80211_BEACON_PARAM_EXTENDED_RATES 0x32 +#define IEEE80211_BEACON_PARAM_TIM 0x05 + + +#define IEEE80211_HEADER_SIZE 24 + +typedef struct beacon_info_t { + uint64_t timestamp; + uint16_t interval; + uint16_t capability; +} QEMU_PACKED beacon_info_t; + +typedef uint8_t macaddr_t[6]; + +#define BROADCAST (uint8_t[]){0xff,0xff,0xff,0xff,0xff,0xff} + +typedef struct mac80211_frame { + struct mac80211_frame_control { + unsigned protocol_version : 2; + unsigned type : 2; + unsigned sub_type : 4; + unsigned to_ds : 1; + unsigned from_ds : 1; + unsigned _flags:6; + } QEMU_PACKED frame_control; + uint16_t duration_id; + macaddr_t receiver_address; + macaddr_t transmitter_address; + macaddr_t address_3; + struct mac80211_sequence_control { + unsigned fragment_number : 4; + unsigned sequence_number : 12; + } QEMU_PACKED sequence_control; + // variable length, 2312 byte plus 4 byte frame-checksum + union { + uint8_t data_and_fcs[2316]; + beacon_info_t beacon_info; + }; + unsigned int frame_length; + int signal_strength; + int pos; + struct mac80211_frame *next_frame; +} QEMU_PACKED mac80211_frame; + +typedef struct access_point_info { + const char *ssid; + int channel; + int sigstrength; + macaddr_t mac_address; +} access_point_info; + +enum esp32_ap_state { + Esp32_WLAN__STATE_NOT_AUTHENTICATED, + Esp32_WLAN__STATE_AUTHENTICATED, + Esp32_WLAN__STATE_ASSOCIATED, + Esp32_WLAN__STATE_STA_NOT_AUTHENTICATED, + Esp32_WLAN__STATE_STA_AUTHENTICATED, + Esp32_WLAN__STATE_STA_ASSOCIATED, + Esp32_WLAN__STATE_STA_DHCP, +}; + +#define Esp32_WLAN__MAX_INJECT_QUEUE_SIZE 20 + +typedef struct { + signed rssi:8; /**< Received Signal Strength Indicator(RSSI) of packet. unit: dBm */ + unsigned rate:5; /**< PHY rate encoding of the packet. Only valid for non HT(11bg) packet */ + unsigned :1; /**< reserved */ + unsigned sig_mode:2; /**< 0: non HT(11bg) packet; 1: HT(11n) packet; 3: VHT(11ac) packet */ + unsigned legacy_length:12; /**< copy of the length */ + unsigned damatch0:1; /* destination matches address0 */ + unsigned damatch1:1; /* destination matches address1 */ + unsigned bssidmatch0:1; /* bssid matches address0 */ + unsigned bssidmatch1:1; /* bssid matches address1 */ + unsigned mcs:7; /**< Modulation Coding Scheme. If is HT(11n) packet, shows the modulation, range from 0 to 76(MSC0 ~ MCS76) */ + unsigned cwb:1; /**< Channel Bandwidth of the packet. 0: 20MHz; 1: 40MHz */ + unsigned :16; /**< reserved */ + unsigned smoothing:1; /**< reserved */ + unsigned not_sounding:1; /**< reserved */ + unsigned :1; /**< reserved */ + unsigned aggregation:1; /**< Aggregation. 0: MPDU packet; 1: AMPDU packet */ + unsigned stbc:2; /**< Space Time Block Code(STBC). 0: non STBC packet; 1: STBC packet */ + unsigned fec_coding:1; /**< Flag is set for 11n packets which are LDPC */ + unsigned sgi:1; /**< Short Guide Interval(SGI). 0: Long GI; 1: Short GI */ + signed noise_floor:8; /**< noise floor of Radio Frequency Module(RF). unit: 0.25dBm*/ + unsigned ampdu_cnt:8; /**< ampdu cnt */ + unsigned channel:4; /**< primary channel on which this packet is received */ + unsigned secondary_channel:4; /**< secondary channel on which this packet is received. 0: none; 1: above; 2: below */ + unsigned :8; /**< reserved */ + unsigned timestamp:32; /**< timestamp. The local time when this packet is received. It is precise only if modem sleep or light sleep is not enabled. unit: microsecond */ + unsigned :32; /**< reserved */ + unsigned :31; /**< reserved */ + unsigned ant:1; /**< antenna number from which this packet is received. 0: WiFi antenna 0; 1: WiFi antenna 1 */ + unsigned sig_len:12; /**< length of packet including Frame Check Sequence(FCS) */ + unsigned sig_len_copy:12; /**< another copy of the length */ + unsigned rx_state:8; /**< state of the packet. 0: no error; others: error numbers which are not public */ +} QEMU_PACKED wifi_pkt_rx_ctrl_t; + +extern int esp32_wifi_channel; + +typedef uint8_t ip4_t[4]; + +#define DHCP_CHADDR_LEN 16 +#define DHCP_SNAME_LEN 64 +#define DHCP_FILE_LEN 128 + +typedef struct ip_header_t { + uint8_t version_size; + uint8_t dscp_ecn; + uint8_t len_h; + uint8_t len_l; + uint32_t z; + uint8_t ttl; + uint8_t protocol; + uint16_t checksum; + ip4_t source_ip; + ip4_t dest_ip; +}ip_header_t ; + +typedef struct udp_header_t { + uint8_t src_port_h; + uint8_t src_port_l; + uint8_t dest_port_h; + uint8_t dest_port_l; + uint8_t len_h; + uint8_t len_l; + uint16_t checksum; +} udp_header_t; + +typedef struct dhcp_t { + uint8_t opcode; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + uint32_t xid; + uint16_t secs; + uint16_t flags; + ip4_t ciaddr; + ip4_t yiaddr; + ip4_t siaddr; + ip4_t giaddr; + uint8_t chaddr[DHCP_CHADDR_LEN]; + char bp_sname[DHCP_SNAME_LEN]; + char bp_file[DHCP_FILE_LEN]; + uint32_t magic_cookie; + uint8_t bp_options[0]; +} dhcp_t; + +typedef struct dhcp_request_t { + ip_header_t ipheader; + udp_header_t udpheader; + dhcp_t dhcp; +} dhcp_request_t; + +#endif // esp32_wlan_h diff --git a/hw/misc/esp32_wlan_packet.c b/hw/misc/esp32_wlan_packet.c new file mode 100644 index 000000000000..ca842dd21504 --- /dev/null +++ b/hw/misc/esp32_wlan_packet.c @@ -0,0 +1,283 @@ +/** + * QEMU WLAN access point emulation + * + * Copyright (c) 2008 Clemens Kolbitsch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Modifications: + * 2008-February-24 Clemens Kolbitsch : + * New implementation based on ne2000.c + * 18/1/22 Martin Johnson : Modified for esp32 wifi emulation + */ + +#include "qemu/osdep.h" + +#include "net/net.h" + +#include "esp32_wlan.h" +#include "esp32_wlan_packet.h" + +// the frame checksum isn't used so just put zero in there. +void insertCRC(mac80211_frame *frame) { + unsigned long crc; + unsigned char *fcs = (unsigned char *)frame; + crc = 0; + memcpy(fcs+frame->frame_length, &crc, 4); + frame->frame_length += 4; +} + +static void add_byte(mac80211_frame *frame, uint8_t data) { + frame->data_and_fcs[frame->pos++]=data; + frame->frame_length=IEEE80211_HEADER_SIZE+frame->pos; +} + +static void add_data(mac80211_frame *frame, int len,uint8_t *data) { + for(int i=0;isequence_control.sequence_number = s->inject_sequence_number++; +} + +static mac80211_frame *new_frame(unsigned type, unsigned subtype) { + mac80211_frame *frame = (mac80211_frame *)malloc(sizeof(mac80211_frame)); + frame->next_frame = NULL; + frame->frame_control.protocol_version = 0; + frame->frame_control.type = type; + frame->frame_control.sub_type = subtype; + frame->frame_control._flags = 0; + frame->frame_control.from_ds = 0; + frame->frame_control.to_ds = 0; + frame->duration_id = 314; + frame->sequence_control.fragment_number = 0; + frame->pos=0; + return frame; +} + +static void add_rates(mac80211_frame *frame) { + add_tag(frame,IEEE80211_BEACON_PARAM_RATES,8,(uint8_t[]){0x8b,0x96,0x82,0x84,0x0c,0x18,0x30,0x60}); + add_tag(frame,IEEE80211_BEACON_PARAM_EXTENDED_RATES,4,(uint8_t[]){0x6c,0x12,0x24,0x48}); +} + +static void add_ssid(mac80211_frame *frame, const char *ssid) { + add_tag(frame,IEEE80211_BEACON_PARAM_SSID,strlen(ssid),(uint8_t *)ssid); +} + +mac80211_frame *Esp32_WLAN_create_beacon_frame(access_point_info *ap) { + mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_BEACON); + frame->signal_strength=ap->sigstrength; + frame->beacon_info.timestamp=qemu_clock_get_ns(QEMU_CLOCK_REALTIME)/1000; + frame->beacon_info.interval=1000; + frame->beacon_info.capability=1; + frame->pos=12; + add_ssid(frame,ap->ssid); + add_rates(frame); + add_tag(frame,IEEE80211_BEACON_PARAM_CHANNEL,1,(uint8_t[]){ap->channel}); + add_tag(frame,IEEE80211_BEACON_PARAM_TIM,4,(uint8_t[]){4,1,3,0,0}); + return frame; +} + +static uint16_t in_cksum(uint16_t *addr, int len) { + int sum = 0; + uint16_t answer = 0; + uint16_t *w = addr; + int nleft = len; + while (nleft > 1) { + sum += *w++; + nleft -= 2; + } + /* mop up an odd byte, if necessary */ + if (nleft == 1) { + *(uint8_t *)(&answer) = *(uint8_t *) w; + sum += answer; + } + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + answer = ~sum; /* truncate to 16 bits */ + return (answer); +} + +static mac80211_frame *Esp32_WLAN_create_dhcp_frame(int cmd_size, uint8_t dhcp_commands[]) { + mac80211_frame *frame=new_frame(IEEE80211_TYPE_DATA,IEEE80211_TYPE_DATA_SUBTYPE_DATA); + frame->frame_control.to_ds=1; + add_data(frame,8,(uint8_t[]){ 0xaa, 0xaa ,0x03 ,00 ,00 ,00 ,8 ,00}); + dhcp_request_t req={ + {.version_size=0x45,.ttl=0xff,.protocol=0x11,.dest_ip={0xff,0xff,0xff,0xff}}, + {.src_port_l=0x44,.dest_port_l=0x43}, + {.htype=1,.hlen=6,.xid=0x1d3d00,.chaddr={0x10,0x01,0x00,0xc4,0x0a,0x24}, + .magic_cookie=0x63538263} + }; + int len=sizeof(req)+cmd_size; + req.ipheader.len_h=len>>8; + req.ipheader.len_l=len&0xff; + len=len-sizeof(ip_header_t); + req.udpheader.len_h=len>>8; + req.udpheader.len_l=len&0xff; + req.ipheader.checksum=in_cksum((void *)&req.ipheader,sizeof(ip_header_t)); + add_data(frame,sizeof(req),(uint8_t *)&req); + add_data(frame,cmd_size,dhcp_commands); + return frame; +} + +mac80211_frame *Esp32_WLAN_create_dhcp_request(uint8_t *ip) { + uint8_t dhcp_commands[]={ + 0x35, 1, 3, + 0x39, 2 ,5 ,0xdc , + 0x32, 4, ip[0],ip[1],ip[2],ip[3], + 0x3d, 0x07, 0x01, 0x3c, 0x61, 0x05, 0x0d, 0x99, 0x24, + 0x37, 0x04, 0x01, 0x03, 0x1c, 0x06, + 0xff, 0, 0 + }; + return Esp32_WLAN_create_dhcp_frame(sizeof(dhcp_commands),dhcp_commands); +} + +mac80211_frame *Esp32_WLAN_create_dhcp_discover(void) { + uint8_t dhcp_commands[]={ + 0x35, 1, 1, + 0x39, 2 ,5 ,0xdc , + 0x0c ,0x09 ,0x65 ,0x73 ,0x70 ,0x72 ,0x65 ,0x73 ,0x73 ,0x69 ,0x66 , + 0x3d ,0x07, 0x01 ,0x3c ,0x61 ,0x05 ,0x0d ,0x99 ,0x24 , + 0x37 ,0x04 ,0x01 ,0x03 ,0x1c ,0x06 , + 0xff, 0,0 + }; + return Esp32_WLAN_create_dhcp_frame(sizeof(dhcp_commands),dhcp_commands); +} + +mac80211_frame *Esp32_WLAN_create_association_request(access_point_info *ap) { + mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_REQ); + add_data(frame,4,(uint8_t []){0x21,4,3,0}); + add_ssid(frame,ap->ssid); + add_rates(frame); + return frame; +} + +mac80211_frame *Esp32_WLAN_create_ack(void) { + mac80211_frame *frame=new_frame(IEEE80211_TYPE_CTL,IEEE80211_TYPE_CTL_SUBTYPE_ACK); + frame->frame_length=10; + return frame; +} + +mac80211_frame *Esp32_WLAN_create_probe_response(access_point_info *ap) { + mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_PROBE_RESP); + frame->beacon_info.timestamp=qemu_clock_get_ns(QEMU_CLOCK_REALTIME)/1000; + frame->beacon_info.interval=1000; + frame->beacon_info.capability=1; + frame->pos=12; + add_ssid(frame,ap->ssid); + add_rates(frame); + add_tag(frame,IEEE80211_BEACON_PARAM_CHANNEL,1,(uint8_t[]){ap->channel}); + return frame; +} + +mac80211_frame *Esp32_WLAN_create_probe_request(access_point_info *ap) { + mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_PROBE_REQ); + memcpy(frame->receiver_address,BROADCAST,6); + memcpy(frame->address_3,BROADCAST,6); + add_ssid(frame,ap->ssid); + add_tag(frame,IEEE80211_BEACON_PARAM_CHANNEL,1,(uint8_t[]){ap->channel}); + add_rates(frame); + return frame; +} + +mac80211_frame *Esp32_WLAN_create_authentication_response(access_point_info *ap) { + mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION); + /* + * Fixed params... typical AP params (6 byte) + * + * They include + * - Authentication Algorithm (here: Open System) + * - Authentication SEQ + * - Status code (successful 0x0) + */ + add_data(frame,6,(uint8_t []){0,0,2,0,0,0}); + add_ssid(frame,ap->ssid); + return frame; +} + +mac80211_frame *Esp32_WLAN_create_authentication_request(void) { + mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION); + /* + * Fixed params... typical AP params (6 byte) + * + * They include + * - Authentication Algorithm (here: Open System) + * - Authentication SEQ + * - Status code (successful 0x0) + */ + //frame->duration_id=0x13a; + add_data(frame,6,(uint8_t []){0,0,1,0,0,0}); + //add_data(frame,11,(uint8_t []){0,0,0,0,0,0,0,0,0,0,0}); + //add_ssid(frame,ap->ssid); + return frame; +} + +mac80211_frame *Esp32_WLAN_create_deauthentication(void) { + mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_DEAUTHENTICATION); + /* + * Insert reason code: + * "Deauthentication because sending STA is leaving" + */ + add_data(frame,2,(uint8_t []){3,0}); + return frame; +} + +mac80211_frame *Esp32_WLAN_create_association_response(access_point_info *ap) { + mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_RESP); + /* + * Fixed params... typical AP params (6 byte) + * + * They include + * - Capability Information + * - Status code (successful 0x0) + * - Association ID + */ + add_data(frame,6,(uint8_t []){33,4,0,0,1,0xc0}); + add_ssid(frame,ap->ssid); + add_rates(frame); + return frame; +} + +mac80211_frame *Esp32_WLAN_create_disassociation(void) { + mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_DISASSOCIATION); + /* + * Insert reason code: + * "Disassociation because sending STA is leaving" + */ + add_data(frame,2,(uint8_t []){3,0}); + return frame; +} + +mac80211_frame *Esp32_WLAN_create_data_packet(Esp32WifiState *s, const uint8_t *buf, int size) { + mac80211_frame *frame=new_frame(IEEE80211_TYPE_DATA,IEEE80211_TYPE_DATA_SUBTYPE_DATA); + + frame->duration_id = 44; + /* LLC */ + add_data(frame,6,(uint8_t[]){ 0xaa, 0xaa ,0x03 ,0 ,0 ,0}); + memcpy(frame->data_and_fcs+6, buf+12, size-12); + frame->frame_length = IEEE80211_HEADER_SIZE + size-6; + return frame; +} diff --git a/hw/misc/esp32_wlan_packet.h b/hw/misc/esp32_wlan_packet.h new file mode 100644 index 000000000000..241aa7f41199 --- /dev/null +++ b/hw/misc/esp32_wlan_packet.h @@ -0,0 +1,56 @@ +/** + * QEMU WLAN access point emulation + * + * Copyright (c) 2008 Clemens Kolbitsch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Modifications: + * 2008-February-24 Clemens Kolbitsch : + * New implementation based on ne2000.c + * 18/1/22 Martin Johnson : Modified for esp32 wifi emulation + * + */ + +#ifndef esp32_wlan_packet_h +#define esp32_wlan_packet_h 1 + +#include "esp32_wlan.h" +#include "hw/misc/esp32_wifi.h" + +void Esp32_WLAN_init_ap_frame(Esp32WifiState *s, struct mac80211_frame *frame); +int Esp32_WLAN_dumpFrame(struct mac80211_frame *frame, int frame_len, char *filename); +void Esp32_WLAN_insert_frame(Esp32WifiState *s, struct mac80211_frame *frame); +struct mac80211_frame *Esp32_WLAN_create_beacon_frame(access_point_info *ap); +struct mac80211_frame *Esp32_WLAN_create_probe_response(access_point_info *ap); +struct mac80211_frame *Esp32_WLAN_create_probe_request(access_point_info *ap); +struct mac80211_frame *Esp32_WLAN_create_authentication_request(void); +struct mac80211_frame *Esp32_WLAN_create_authentication_response(access_point_info *ap); +struct mac80211_frame *Esp32_WLAN_create_deauthentication(void); +struct mac80211_frame *Esp32_WLAN_create_association_request(access_point_info *ap); +struct mac80211_frame *Esp32_WLAN_create_association_response(access_point_info *ap); +struct mac80211_frame *Esp32_WLAN_create_disassociation(void); +struct mac80211_frame *Esp32_WLAN_create_data_reply(Esp32WifiState *s, struct mac80211_frame *incoming); +struct mac80211_frame *Esp32_WLAN_create_data_packet(Esp32WifiState *s, const uint8_t *buf, int size); +struct mac80211_frame *Esp32_WLAN_create_ack(void); +struct mac80211_frame *Esp32_WLAN_create_dhcp_discover(void); +struct mac80211_frame *Esp32_WLAN_create_dhcp_request(uint8_t *ip); +void insertCRC(mac80211_frame *frame); + +#endif // esp32_wlan_packet_h diff --git a/hw/misc/esp32c3_aes.c b/hw/misc/esp32c3_aes.c new file mode 100644 index 000000000000..90a1b7f1ebe6 --- /dev/null +++ b/hw/misc/esp32c3_aes.c @@ -0,0 +1,474 @@ +/* + * ESP32-C3 AES emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32c3_aes.h" +#include "qemu/error-report.h" +#include +#include +#include "hw/irq.h" +#include "crypto/aes.h" + +#define AES_WARNING 0 +#define AES_DEBUG 0 + + +static void esp32c3_aes_dma_exit(ESP32C3AesState *s) +{ + s->state_reg = ESP32C3_AES_IDLE; +} + +static void* esp32c3_aes_get_buffer(uint32_t size) +{ + /* Instead of reallocating a buffer every time, keep a watermark and a single buffer */ + static void* buffer = NULL; + static uint32_t buf_size = 0; + + if (buf_size < size) { + buffer = g_realloc(buffer, size); + buf_size = size; + } + + return buffer; +} + + +/** + * @brief Interpret data in IV memory as a counter and add a block count to its value. + * Used in CTR block mode. + */ +static void esp32c3_aes_ctr_add_counter(ESP32C3AesState *s, uint32_t blocks) +{ + /* Check the length of this counter in bits. In both cases, it is stored in BIG-ENDIAN */ + if (FIELD_EX32(s->inc_sel_reg, AES_INC_SEL_REG, AES_INC_SEL) == 1) { + /* 128-bit mode, no native 128 integer type, use two 64-bit types */ + uint64_t* low_ptr = (uint64_t*) (s->iv_mem + sizeof(uint64_t)); + uint64_t* high_ptr = (uint64_t*) s->iv_mem; + const uint64_t original = be64toh(*low_ptr); + uint64_t value = original + blocks; + *low_ptr = htobe64(value); + /* If the value overflowed, we have to update the upper part too */ + if (original > value) { + value = be64toh(*high_ptr) + 1; + *high_ptr = htobe64(value); + } + } else { + /* 32-bit mode */ + uint32_t* counter_ptr = (uint32_t*) &s->iv_mem[ESP32C3_AES_IV_REG_CNT - sizeof(uint32_t)]; + const uint32_t value = be32toh(*counter_ptr) + blocks; + *counter_ptr = htobe32(value); + } +} + + +static void esp32c3_aes_dma_start(ESP32C3AesState *s) +{ + gcry_cipher_hd_t ghandle; + uint32_t gdma_out_idx; + uint32_t gdma_in_idx; + + const enum gcry_cipher_modes cipher_map[ESP32C3_AES_CIPHER_COUNT] = { + [ESP32C3_AES_ECB_CIPHER] = GCRY_CIPHER_MODE_ECB, + [ESP32C3_AES_CBC_CIPHER] = GCRY_CIPHER_MODE_CBC, + [ESP32C3_AES_OFB_CIPHER] = GCRY_CIPHER_MODE_OFB, + [ESP32C3_AES_CTR_CIPHER] = GCRY_CIPHER_MODE_CTR, + [ESP32C3_AES_CFB8_CIPHER] = GCRY_CIPHER_MODE_CFB8, + [ESP32C3_AES_CFB128_CIPHER] = GCRY_CIPHER_MODE_CFB, + }; + + /* Get the block Cipher mode */ + const uint32_t cipher_mode = FIELD_EX32(s->block_mode_reg , AES_BLK_MODE_REG, AES_BLOCK_MODE); + + /* Check whether we have to encrypt or decrypt */ + const uint32_t mode = FIELD_EX32(s->mode_reg , AES_MODE_REG, AES_MODE); + const bool encrypt = (mode == ESP32C3_AES_MODE_128_ENC) || (mode == ESP32C3_AES_MODE_256_ENC); + const bool decrypt = (mode == ESP32C3_AES_MODE_128_DEC) || (mode == ESP32C3_AES_MODE_256_DEC); + + /* Get the length, in bits of the key */ + const int length = (mode == ESP32C3_AES_MODE_128_ENC || mode == ESP32C3_AES_MODE_128_DEC) ? 128 : 256; + const int algo = length == 128 ? GCRY_CIPHER_AES128 : GCRY_CIPHER_AES256; + + if (cipher_mode >= ESP32C3_AES_CIPHER_COUNT) { + error_report("[AES] Invalid or unsupported Cipher block mode!"); + return; + } else if (!decrypt && !encrypt) { + error_report("[AES] Invalid mode!"); + return; + } + + gcry_error_t err = gcry_cipher_open(&ghandle, algo, cipher_map[cipher_mode], 0); + if (err) { + error_report("[AES] error 0x%x when opening cipher", err); + return; + } + + /* Cast the keys and data to byte array. + * This can only work as-is if the host computer is has a little-endian CPU. */ + const uint8_t* key = (uint8_t*) &s->key; + uint8_t* iv_mem = (uint8_t*) &s->iv_mem; + + /* Set the algorithm key */ + err = gcry_cipher_setkey(ghandle, key, length / 8); + if (err) { + error_report("[AES] error 0x%x setting key", err); + goto close_exit; + } + + /* `iv_mem` field represents the Initialization Vector for CBC/OFB/CFB operations + * But it represents the Initial Counter Block for CTR operation. + * It shall be ignored for ECB block operation. */ + if (cipher_mode == ESP32C3_AES_CTR_CIPHER) { + err = gcry_cipher_setctr(ghandle, iv_mem, ESP32C3_AES_IV_REG_CNT); + } else if (cipher_mode != ESP32C3_AES_ECB_CIPHER) { + err = gcry_cipher_setiv(ghandle, iv_mem, ESP32C3_AES_IV_REG_CNT); + } + + if (err) { + error_report("[AES] error 0x%x setting IV memory", err); + goto close_exit; + } + + /* Get the GDMA input channel index for AES peripheral */ + assert(s->gdma != NULL); + + if ( !esp32c3_gdma_get_channel_periph(s->gdma, GDMA_AES, ESP32C3_GDMA_OUT_IDX, &gdma_out_idx) || + !esp32c3_gdma_get_channel_periph(s->gdma, GDMA_AES, ESP32C3_GDMA_IN_IDX, &gdma_in_idx) ) { + warn_report("[AES] GDMA requested but no properly configured channel found"); + goto close_exit; + } + + /* Block number represents the number of 128-bit (16-byte) blocks to encrypt. + * If block_num_reg is 100, we have to encrypt 100*128/8 = 1600 bytes */ + uint32_t buf_size = s->block_num_reg * 16; + uint8_t* buffer = esp32c3_aes_get_buffer(buf_size); + + if ( !esp32c3_gdma_read_channel(s->gdma, gdma_out_idx, buffer, buf_size) ) { + warn_report("[AES] Error reading from GDMA buffer"); + goto close_exit; + } + + /* Reading was successful, process the buffer (encrypt/decrypt) and write back to the GDMA OUT buffer */ + if (encrypt) { + err = gcry_cipher_encrypt(ghandle, buffer, buf_size, NULL, 0); + + if (cipher_mode != ESP32C3_AES_CTR_CIPHER) { + /* On the real hardware, IV memory is used in-place for encrypting data, so copy the last encrypted block to IV memory */ + memcpy(iv_mem, buffer + buf_size - 16, ESP32C3_AES_IV_REG_CNT); + } + } else { + /* Store the last block of plaintext, needed for OFB */ + const uint8_t* buffer_last_block = buffer + buf_size - ESP32C3_AES_IV_REG_CNT; + uint8_t plaintext[ESP32C3_AES_IV_REG_CNT]; + memcpy(plaintext, buffer_last_block, ESP32C3_AES_IV_REG_CNT); + + /* The IV memory is initalized with the encrypted data, so do the copy now */ + if (cipher_mode != ESP32C3_AES_OFB_CIPHER && cipher_mode != ESP32C3_AES_CTR_CIPHER) { + memcpy(iv_mem, buffer + buf_size - 16, ESP32C3_AES_IV_REG_CNT); + } + + err = gcry_cipher_decrypt(ghandle, buffer, buf_size, NULL, 0); + + /* For OFB, it is done after the decryption. Moreover, the hardware XOR the original plaintext with the output + * and stores the result in IV memory. */ + if (cipher_mode == ESP32C3_AES_OFB_CIPHER) { + for (int i = 0; i < ESP32C3_AES_IV_REG_CNT; i++) { + iv_mem[i] = buffer_last_block[i] ^ plaintext[i]; + } + } + } + + if (cipher_mode == ESP32C3_AES_CTR_CIPHER) { + esp32c3_aes_ctr_add_counter(s, s->block_num_reg); + } + + if (err) { + error_report("[AES] error processing memory"); + goto close_exit; + } + + if ( !esp32c3_gdma_write_channel(s->gdma, gdma_in_idx, buffer, buf_size) ) { + warn_report("[AES] Error writing to GDMA buffer"); + goto close_exit; + } + + s->state_reg = ESP32C3_AES_DONE; + + if (s->int_ena_reg) { + qemu_irq_raise(s->irq); + } + +close_exit: + gcry_cipher_close(ghandle); +} + + +static void esp32c3_aes_start(ESP32C3AesState *s) +{ + AES_KEY aes_key; + + /* Check whether we have to encrypt or decrypt */ + const uint32_t mode = FIELD_EX32(s->mode_reg , AES_MODE_REG, AES_MODE); + const bool encrypt = (mode == ESP32C3_AES_MODE_128_ENC) || (mode == ESP32C3_AES_MODE_256_ENC); + const bool decrypt = (mode == ESP32C3_AES_MODE_128_DEC) || (mode == ESP32C3_AES_MODE_256_DEC); + + /* Get the length, in bits of the key */ + const int length = (mode == ESP32C3_AES_MODE_128_ENC || mode == ESP32C3_AES_MODE_128_DEC) ? 128 : 256; + + /* Cast the keys and data to byte array. + * This can only work as-is if the host computer is has a little-endian CPU. */ + const uint8_t* key = (uint8_t*) &s->key; + const uint8_t* tin = (uint8_t*) &s->text_in; + uint8_t* tout = (uint8_t*) &s->text_out; + + if (encrypt) { + + AES_set_encrypt_key(key, length, &aes_key); + AES_encrypt(tin, tout, &aes_key); + + } else if (decrypt) { + + AES_set_decrypt_key(key, length, &aes_key); + AES_decrypt(tin, tout, &aes_key); + + } + + s->state_reg = ESP32C3_AES_IDLE; +} + +static uint64_t esp32c3_aes_read(void *opaque, hwaddr addr, unsigned int size) +{ + ESP32C3AesState *s = ESP32C3_AES(opaque); + uint64_t r = 0; + + /* At the moment, make the assumption that we always write a 32-bit word, except for IV memory */ + assert((addr >= A_AES_IV_MEM_0_REG && addr <= A_AES_IV_MEM_15_REG) || + size == sizeof(uint32_t)); + + switch (addr) { + case A_AES_KEY_0_REG ... A_AES_KEY_7_REG: + r = s->key[(addr - A_AES_KEY_0_REG) / sizeof(uint32_t)]; + break; + + case A_AES_TEXT_IN_0_REG ... A_AES_TEXT_IN_3_REG: + r = s->text_in[(addr - A_AES_TEXT_IN_0_REG) / sizeof(uint32_t)]; + break; + + case A_AES_TEXT_OUT_0_REG ... A_AES_TEXT_OUT_3_REG: + r = s->text_out[(addr - A_AES_TEXT_OUT_0_REG) / sizeof(uint32_t)]; + break; + + case A_AES_IV_MEM_0_REG ... A_AES_IV_MEM_15_REG: + /* Use r as the offset */ + r = addr - A_AES_IV_MEM_0_REG; + if (size == sizeof(uint32_t)) { + r = *((uint32_t*) (s->iv_mem + r)); + } else if (size == sizeof(uint8_t)) { + r = s->iv_mem[r]; + } + break; + + case A_AES_STATE_REG: + r = s->state_reg; + break; + + case A_AES_MODE_REG: + r = s->mode_reg; + break; + + case A_AES_DMA_ENA_REG: + r = s->dma_enable_reg; + break; + + case A_AES_BLK_MODE_REG: + r = s->block_mode_reg; + break; + + case A_AES_BLK_NUM_REG: + r = s->block_num_reg; + break; + + case A_AES_INC_SEL_REG: + r = s->inc_sel_reg; + break; + + case A_AES_INT_ENA_REG: + r = s->int_ena_reg; + break; + + default: +#if AES_WARNING + /* Other registers are not supported yet */ + warn_report("[AES] Unsupported read to %08lx", addr); +#endif + break; + } + +#if AES_DEBUG + info_report("[AES] Reading from %08lx (%08lx)", addr, r); +#endif + + + return r; +} + + +static void esp32c3_aes_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + ESP32C3AesState *s = ESP32C3_AES(opaque); + uint32_t offset = 0; + + /* At the moment, make the assumption that we always write a 32-bit word, except for IV memory */ + assert((addr >= A_AES_IV_MEM_0_REG && addr <= A_AES_IV_MEM_15_REG) || + size == sizeof(uint32_t)); + + switch (addr) { + case A_AES_KEY_0_REG ... A_AES_KEY_7_REG: + s->key[(addr - A_AES_KEY_0_REG) / sizeof(uint32_t)] = value; + break; + + case A_AES_TEXT_IN_0_REG ... A_AES_TEXT_IN_3_REG: + s->text_in[(addr - A_AES_TEXT_IN_0_REG) / sizeof(uint32_t)] = value; + break; + + case A_AES_IV_MEM_0_REG ... A_AES_IV_MEM_15_REG: + offset = addr - A_AES_IV_MEM_0_REG; + if (size == sizeof(uint32_t)) { + *((uint32_t*) (s->iv_mem + offset)) = value; + } else if (size == sizeof(uint8_t)) { + s->iv_mem[offset] = value & 0xff; + } + break; + + case A_AES_MODE_REG: + s->mode_reg = value; + break; + + case A_AES_TRIGGER_REG: + if (FIELD_EX32(value, AES_TRIGGER_REG, AES_TRIGGER)) { + /* DMA mode is different than "regular" mode */ + if (FIELD_EX32(s->dma_enable_reg , AES_DMA_ENA_REG, AES_DMA_ENA) != 0) { + esp32c3_aes_dma_start(s); + } else { + esp32c3_aes_start(s); + } + } + break; + + case A_AES_DMA_ENA_REG: + s->dma_enable_reg = value; + break; + + case A_AES_BLK_MODE_REG: + s->block_mode_reg = value; + break; + + case A_AES_BLK_NUM_REG: + s->block_num_reg = value; + break; + + case A_AES_INC_SEL_REG: + s->inc_sel_reg = value; + break; + + case A_AES_INT_CLR_REG: + if (FIELD_EX32(value, AES_INT_CLR_REG, AES_INT_CLR)) { + qemu_irq_lower(s->irq); + } + break; + + case A_AES_INT_ENA_REG: + s->int_ena_reg = FIELD_EX32(value, AES_INT_ENA_REG, AES_INT_ENA) ? 1 : 0; + break; + + case A_AES_DMA_EXIT_REG: + esp32c3_aes_dma_exit(s); + break; + + default: +#if AES_WARNING + /* Other registers are not supported yet */ + warn_report("[AES] Unsupported write to %08lx (%08lx)", addr, value); +#endif + break; + } + +#if AES_DEBUG + info_report("[AES] Writing to %08lx (%08lx)", addr, value); +#endif + +} + +static const MemoryRegionOps esp32c3_aes_ops = { + .read = esp32c3_aes_read, + .write = esp32c3_aes_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32c3_aes_reset(DeviceState *dev) +{ + ESP32C3AesState *s = ESP32C3_AES(dev); + memset(s->key, 0, ESP32C3_AES_KEY_REG_CNT * sizeof(uint32_t)); + memset(s->text_in, 0, ESP32C3_AES_TEXT_REG_CNT * sizeof(uint32_t)); + memset(s->text_out, 0, ESP32C3_AES_TEXT_REG_CNT * sizeof(uint32_t)); + + s->state_reg = ESP32C3_AES_IDLE; + s->mode_reg = 0; + s->dma_enable_reg = 0; + s->block_mode_reg = 0; + s->block_num_reg = 0; + s->inc_sel_reg = 0; + s->int_ena_reg = 0; +} + +static void esp32c3_aes_realize(DeviceState *dev, Error **errp) +{ + ESP32C3AesState *s = ESP32C3_AES(dev); + + /* Make sure GDMA was set of issue an error */ + if (s->gdma == NULL) { + error_report("[AES] GDMA controller must be set!"); + } +} + +static void esp32c3_aes_init(Object *obj) +{ + ESP32C3AesState *s = ESP32C3_AES(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32c3_aes_ops, s, + TYPE_ESP32C3_AES, ESP32C3_AES_REGS_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + + sysbus_init_irq(sbd, &s->irq); +} + +static void esp32_aes_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = esp32c3_aes_realize; + dc->reset = esp32c3_aes_reset; +} + +static const TypeInfo esp32c3_aes_info = { + .name = TYPE_ESP32C3_AES, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32C3AesState), + .instance_init = esp32c3_aes_init, + .class_init = esp32_aes_class_init +}; + +static void esp32c3_aes_register_types(void) +{ + type_register_static(&esp32c3_aes_info); +} + +type_init(esp32c3_aes_register_types) diff --git a/hw/misc/esp32c3_cache.c b/hw/misc/esp32c3_cache.c new file mode 100644 index 000000000000..c9cfe7cf92db --- /dev/null +++ b/hw/misc/esp32c3_cache.c @@ -0,0 +1,272 @@ +/* + * ESP32-C3 ICache emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/misc/esp32c3_cache.h" +#include "sysemu/block-backend-io.h" + + +#define CACHE_DEBUG 0 +#define CACHE_WARNING 0 + + +/** + * @brief Checks that the enable flag is enabled in the I/O register. If that's the case, + * `done` flag is returned and the `enable` flag is cleared from register. + * Else, 0 is returned. +*/ +static inline uint32_t check_and_reset_ena(uint32_t* hwreg, uint32_t ena_mask, uint32_t done_mask) +{ + uint32_t regval = *hwreg; + + if (regval & ena_mask) { + regval &= ~ena_mask; + regval |= done_mask; + *hwreg = regval; + } + + return regval; +} + + +static inline uint32_t esp32c3_read_mmu_value(ESP32C3CacheState *s, hwaddr reg_addr) +{ + /* Make the assumption that the address is aligned on sizeof(uint32_t) */ + const uint32_t index = reg_addr / sizeof(uint32_t); + return (uint32_t) s->mmu[index].val; +} + + +static inline void esp32c3_write_mmu_value(ESP32C3CacheState *s, hwaddr reg_addr, uint32_t value) +{ + /* Make the assumption that the address is aligned on sizeof(uint32_t) */ + const uint32_t index = reg_addr / sizeof(uint32_t); + /* Reserved bits shall always be 0 */ + ESP32C3MMUEntry e = { .val = value }; + /* Always keep reserved as 0 */ + e.reserved = 0; + if (s->mmu[index].val != e.val) { + assert(s->flash_blk != NULL); + /* Update the cache (MemoryRegion) */ + const uint32_t virtual_address = index * ESP32C3_PAGE_SIZE; + /* The entry contains the index of the 64KB block from the flash memory */ + const uint32_t physical_address = e.page_number * ESP32C3_PAGE_SIZE; + uint8_t* cache_data = ((uint8_t*) memory_region_get_ram_ptr(&s->dcache)) + virtual_address; + + if (e.invalid) { + const uint32_t invalid_value = 0xdeadbeef; + uint32_t* cache_word_data = (uint32_t*) cache_data; + for (int i = 0; i < ESP32C3_PAGE_SIZE / sizeof(invalid_value); i++) { + cache_word_data[i] = invalid_value; + } + } else { + blk_pread(s->flash_blk, physical_address, ESP32C3_PAGE_SIZE, cache_data, 0); + } + + s->mmu[index].val = e.val; + } +} + + +static uint64_t esp32c3_cache_read(void *opaque, hwaddr addr, unsigned int size) +{ + ESP32C3CacheState *s = ESP32C3_CACHE(opaque); + const hwaddr index = ESP32C3_CACHE_REG_IDX(addr); + uint64_t r = 0; + + if (addr & 0x3) { + /* Unaligned access, should we fail? */ + error_report("[QEMU] unaligned access to the cache registers"); + } + + switch(addr) { + case A_EXTMEM_ICACHE_CTRL: + r = s->icache_enable; + break; + /* For the following registers, mark the bit as done only if the feature was enabled */ + case A_EXTMEM_ICACHE_SYNC_CTRL: + r = check_and_reset_ena(&s->regs[index], + R_EXTMEM_ICACHE_SYNC_CTRL_INVALIDATE_ENA_MASK, + R_EXTMEM_ICACHE_SYNC_CTRL_SYNC_DONE_MASK); + break; + case A_EXTMEM_ICACHE_AUTOLOAD_CTRL: + r = check_and_reset_ena(&s->regs[index], + R_EXTMEM_ICACHE_AUTOLOAD_CTRL_AUTOLOAD_ENA_MASK, + R_EXTMEM_ICACHE_AUTOLOAD_CTRL_AUTOLOAD_DONE_MASK); + break; + case A_EXTMEM_ICACHE_PRELOAD_CTRL: + r = check_and_reset_ena(&s->regs[index], + R_EXTMEM_ICACHE_PRELOAD_CTRL_PRELOAD_ENA_MASK, + R_EXTMEM_ICACHE_PRELOAD_CTRL_PRELOAD_DONE_MASK); + break; + case A_EXTMEM_ICACHE_FREEZE: + r = s->regs[index]; + break; + case A_EXTMEM_CACHE_STATE: + /* Return the state of ICache as idle: + * 1: Idle + * 0: Busy/Not idle */ + r = 1 << R_EXTMEM_CACHE_STATE_ICACHE_STATE_SHIFT; + break; + case ESP32C3_MMU_TABLE_OFFSET ... (ESP32C3_MMU_TABLE_OFFSET + ESP32C3_MMU_SIZE): + r = esp32c3_read_mmu_value(s, addr - ESP32C3_MMU_TABLE_OFFSET); + break; + default: +#if CACHE_WARNING + warn_report("[CACHE] Unsupported read to 0x%lx", addr); +#endif + break; + } + +#if CACHE_DEBUG + info_report("[CACHE] Reading 0x%lx (0x%lx)", addr, r); +#endif + + return r; +} + +static void esp32c3_cache_write(void *opaque, hwaddr addr, uint64_t value, + unsigned int size) +{ + ESP32C3CacheState *s = ESP32C3_CACHE(opaque); + + const hwaddr index = ESP32C3_CACHE_REG_IDX(addr); + + if (index < ESP32C3_CACHE_REG_COUNT) { + switch (addr) { + case A_EXTMEM_ICACHE_CTRL: + s->icache_enable = value & 1; + break; + case A_EXTMEM_ICACHE_FREEZE: + if (value & R_EXTMEM_ICACHE_FREEZE_ICACHE_FREEZE_ENA_MASK) { + /* Enable freeze, set DONE bit */ + s->regs[index] |= R_EXTMEM_ICACHE_FREEZE_ICACHE_FREEZE_DONE_MASK; + } else { + /* Disable freeze, clear DONE bit */ + s->regs[index] &= ~R_EXTMEM_ICACHE_FREEZE_ICACHE_FREEZE_DONE_MASK; + } + break; + default: + s->regs[index] = value; + break; + } + } else if (addr >= ESP32C3_MMU_TABLE_OFFSET) { + esp32c3_write_mmu_value(s, addr - ESP32C3_MMU_TABLE_OFFSET, value); + } + +#if CACHE_DEBUG + info_report("[CACHE] Writing 0x%lx = %08lx", addr, value); +#endif + +} + +static const MemoryRegionOps esp32c3_cache_ops = { + .read = esp32c3_cache_read, + .write = esp32c3_cache_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static bool esp32c3_cache_mem_accepts(void *opaque, hwaddr addr, + unsigned size, bool is_write, + MemTxAttrs attrs) +{ + /* Only accept operation in the cache if there are in READ access. + * TODO: Refuse any access to the cache if disable and trigger an exception. */ + return !is_write; +} + +static const MemoryRegionOps esp32c3_cache_mem_ops = { + .write = NULL, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid.accepts = esp32c3_cache_mem_accepts, +}; + +static void esp32c3_cache_reset(DeviceState *dev) +{ + ESP32C3CacheState *s = ESP32C3_CACHE(dev); + memset(s->regs, 0, ESP32C3_CACHE_REG_COUNT * sizeof(*s->regs)); + + /* Initialize the MMU with invalid entries */ + for (int i = 0; i < ESP32C3_MMU_TABLE_ENTRY_COUNT; i++) { + s->mmu[i].invalid = 1; + } + + /* On reset, autoload must be set to done (ready) */ + s->regs[ESP32C3_CACHE_REG_IDX(A_EXTMEM_ICACHE_AUTOLOAD_CTRL)] = R_EXTMEM_ICACHE_AUTOLOAD_CTRL_AUTOLOAD_DONE_MASK; + /* Same goes for the manual preload */ + s->regs[ESP32C3_CACHE_REG_IDX(A_EXTMEM_ICACHE_PRELOAD_CTRL)] = R_EXTMEM_ICACHE_PRELOAD_CTRL_PRELOAD_DONE_MASK; +} + +static void esp32c3_cache_realize(DeviceState *dev, Error **errp) +{ + /* Initialize the registers */ + esp32c3_cache_reset(dev); +} + +static void esp32c3_cache_init(Object *obj) +{ + ESP32C3CacheState *s = ESP32C3_CACHE(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + /* Since the cache I/O region and the MMU I/O region are adjacent, let's use the same MemoryRegion object + * for both, this will simplify the machine architecture. */ + memory_region_init_io(&s->iomem, obj, &esp32c3_cache_ops, s, + TYPE_ESP32C3_CACHE, TYPE_ESP32C3_CACHE_IO_SIZE + ESP32C3_MMU_SIZE); + + /* Initialize the data cache area first */ + s->dcache_base = ESP32C3_DCACHE_BASE; + memory_region_init_rom_device(&s->dcache, OBJECT(s), + &esp32c3_cache_mem_ops, s, + "cpu0-dcache", ESP32C3_EXTMEM_REGION_SIZE, &error_abort); + + /* Same goes for the instruction cache */ + s->icache_base = ESP32C3_ICACHE_BASE; + memory_region_init_alias(&s->icache, OBJECT(s), "cpu0-icache", &s->dcache, 0, ESP32C3_EXTMEM_REGION_SIZE); + + sysbus_init_mmio(sbd, &s->iomem); +} + +static Property esp32c3_cache_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32c3_cache_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32c3_cache_reset; + dc->realize = esp32c3_cache_realize; + device_class_set_props(dc, esp32c3_cache_properties); +} + +static const TypeInfo esp32c3_cache_info = { + .name = TYPE_ESP32C3_CACHE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32C3CacheState), + .instance_init = esp32c3_cache_init, + .class_init = esp32c3_cache_class_init +}; + +static void esp32c3_cache_register_types(void) +{ + type_register_static(&esp32c3_cache_info); +} + +type_init(esp32c3_cache_register_types) diff --git a/hw/misc/esp32c3_jtag.c b/hw/misc/esp32c3_jtag.c new file mode 100644 index 000000000000..2d09c5d6cef6 --- /dev/null +++ b/hw/misc/esp32c3_jtag.c @@ -0,0 +1,80 @@ +/* + * ESP32-C3 USB Serial JTAG emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/error-report.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32c3_jtag.h" + + +static uint64_t esp32c3_jtag_read(void *opaque, hwaddr addr, unsigned int size) +{ + ESP32C3UsbJtagState *s = ESP32C3_JTAG(opaque); + (void) s; + return 0; +} + +static void esp32c3_jtag_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size) +{ + ESP32C3UsbJtagState *s = ESP32C3_JTAG(opaque); + (void) s; +} + +static const MemoryRegionOps esp32c3_jtag_ops = { + .read = esp32c3_jtag_read, + .write = esp32c3_jtag_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32c3_jtag_reset(DeviceState *dev) +{ + (void) dev; +} + +static void esp32c3_jtag_realize(DeviceState *dev, Error **errp) +{ + (void) dev; + (void) errp; +} + +static void esp32c3_jtag_init(Object *obj) +{ + ESP32C3UsbJtagState *s = ESP32C3_JTAG(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32c3_jtag_ops, s, + TYPE_ESP32C3_JTAG, ESP32C3_JTAG_REGS_SIZE); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void esp32c3_jtag_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32c3_jtag_reset; + dc->realize = esp32c3_jtag_realize; +} + +static const TypeInfo esp32c3_jtag_info = { + .name = TYPE_ESP32C3_JTAG, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32C3UsbJtagState), + .instance_init = esp32c3_jtag_init, + .class_init = esp32c3_jtag_class_init +}; + +static void esp32c3_jtag_types(void) +{ + type_register_static(&esp32c3_jtag_info); +} + +type_init(esp32c3_jtag_types) diff --git a/hw/misc/esp32c3_rsa.c b/hw/misc/esp32c3_rsa.c new file mode 100644 index 000000000000..545e0af23e67 --- /dev/null +++ b/hw/misc/esp32c3_rsa.c @@ -0,0 +1,425 @@ +/* + * ESP32-C3 RSA accelerator + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/boards.h" +#include "hw/misc/esp32c3_rsa.h" +#include "hw/irq.h" +#include + +#define ESP32C3_RSA_REGS_SIZE (A_RSA_DATE_REG + 4) + +#define RSA_WARNING 0 + +static void copy_reversed(unsigned char* dest, size_t dst_size, const unsigned char* src, size_t src_size); +static bool mpi_block_to_gcrypt(const uint32_t* mem_block, size_t n_bytes, gcry_mpi_t *out); +static bool mpi_gcrypt_to_block(gcry_mpi_t in, uint32_t* mem_block); +static void esp32c3_rsa_exp_mod(ESP32C3RsaState *s); +static void esp32c3_rsa_modmul_start(ESP32C3RsaState *s); + +/** + * Convert between libgcrypt big-endian representation and little-endian hardware, or vice versa. + * src_size should not exceed dst_size. The remaining part of dst is filled with 0. + */ +static void copy_reversed(unsigned char* dst, size_t dst_size, const unsigned char* src, size_t src_size) +{ + assert(src_size <= dst_size); + size_t i; + for (i = 0; i < src_size; ++i) { + dst[i] = src[src_size - i - 1]; + } + for (; i < dst_size; ++i) { + dst[i] = 0; + } +} + + +/** + * Converts the little-endian memory block of the RSA peripheral to a new gcry_mpi_t object. + * The caller is responsible for freeing the returned object. + */ +static bool mpi_block_to_gcrypt(const uint32_t* mem_block, size_t n_bytes, gcry_mpi_t *out) +{ + size_t scanned; + const unsigned char* mem_u8 = (const unsigned char*) mem_block; + unsigned char temp_buffer[ESP32C3_RSA_MEM_BLK_SIZE] = {}; + copy_reversed(temp_buffer, n_bytes, mem_u8, n_bytes); + gcry_error_t err = gcry_mpi_scan(out, GCRYMPI_FMT_USG, temp_buffer, n_bytes, &scanned); + if (err) { + error_report("%s: gcry_mpi_scan failed with error: %s (%d)", __func__, gcry_strerror(err), err); + return false; + } + if (scanned != n_bytes) { + error_report("%s: gcry_mpi_scan scanned %zu, expected %zu", __func__, scanned, n_bytes); + return false; + } + return true; +} + + +/** + * Copies an MPI from gcry_mpi_t object to the RSA peripheral memory block. + */ +static bool mpi_gcrypt_to_block(gcry_mpi_t in, uint32_t* mem_block) +{ + size_t written; + unsigned char* mem_u8 = (unsigned char*) mem_block; + unsigned char temp_buffer[ESP32C3_RSA_MEM_BLK_SIZE] = {}; + gcry_error_t err = gcry_mpi_print(GCRYMPI_FMT_USG, temp_buffer, ESP32C3_RSA_MEM_BLK_SIZE, &written, in); + if (err) { + error_report("%s: gcry_mpi_print failed with error: %s (%d)", __func__, gcry_strerror(err), err); + return false; + } + copy_reversed(mem_u8, ESP32C3_RSA_MEM_BLK_SIZE, temp_buffer, written); + return true; +} + + +/** Calculates Z_MEM = X_MEM ^ Y_MEM mod M_MEM. + * Unlike the real hardware, doesn't use the mprime register. + */ +static void esp32c3_rsa_exp_mod(ESP32C3RsaState *s) +{ + gcry_mpi_t x, y, z, m; + + /* Get the length of the operands in bytes. Register mode_reg designates the length + * in 32-bit words. */ + size_t n_bytes = (s->mode_reg + 1) * 4; + + /* Convert inputs to gcry_mpi_t */ + if (!mpi_block_to_gcrypt(s->x_mem, n_bytes, &x)) { + goto error_ret; + } + if (!mpi_block_to_gcrypt(s->y_mem, n_bytes, &y)) { + goto error_x; + } + if (!mpi_block_to_gcrypt(s->m_mem, n_bytes, &m)) { + goto error_y; + } + + /* calculate the result and write it back */ + z = gcry_mpi_new(n_bytes * 8); + gcry_mpi_powm(z, x, y, m); + mpi_gcrypt_to_block(z, s->z_mem); + + /* Trigger an interrupt on completion */ + if (s->int_ena) { + qemu_set_irq(s->irq, 1); + } + + /* Clean up */ + gcry_mpi_release(m); + gcry_mpi_release(z); +error_y: + gcry_mpi_release(y); +error_x: + gcry_mpi_release(x); +error_ret: + return; +} + + +/* Calculates Z_MEM = X_MEM * Y_MEM mod M_MEM. */ +static void esp32c3_rsa_modmul_start(ESP32C3RsaState *s) +{ + assert(s->mode_reg < (1 << 7)); + gcry_mpi_t m, x, z, y; + + /* In this mode, the output and input lengths are the same, mode_reg represents the length of + * the operands in 32-bit word. Multiply by 4 to get the size in bytes. */ + const size_t n_bytes = (s->mode_reg + 1) * 4; + + /* Convert inputs to gcry_mpi_t */ + if (!mpi_block_to_gcrypt(s->x_mem, n_bytes, &x)) { + goto error_ret; + } + if (!mpi_block_to_gcrypt(s->y_mem, n_bytes, &y)) { + goto error_x; + } + if (!mpi_block_to_gcrypt(s->m_mem, n_bytes, &m)) { + goto error_y; + } + + z = gcry_mpi_new(n_bytes * 8 * 2); + + /* Z = X * Y mod M */ + gcry_mpi_mulm(z, x, y, m); + + /* Write back */ + mpi_gcrypt_to_block(z, s->z_mem); + + /* Trigger an interrupt on completion */ + if (s->int_ena) { + qemu_set_irq(s->irq, 1); + } + + /* Clean up */ + gcry_mpi_release(z); + gcry_mpi_release(m); +error_y: + gcry_mpi_release(y); +error_x: + gcry_mpi_release(x); +error_ret: + return; +} + + +/** Calculates Z_MEM = X_MEM * Z_MEM */ +static void esp32c3_rsa_mul_start(ESP32C3RsaState *s) +{ + /* In this mode, the output length, in 32-bit word, is set by mode_reg. The input is length / 2. + * Thus, multiply mode_reg by 4 to get the number of bytes. */ + size_t n_bytes = (s->mode_reg + 1) * 4; + size_t n_bytes_input = n_bytes / 2; + + memcpy(s->z_mem, s->z_mem + n_bytes_input / sizeof(uint32_t), n_bytes_input); + memset(s->z_mem + n_bytes_input / sizeof(uint32_t), 0, n_bytes_input); + + /* Convert inputs to gcry_mpi_t */ + gcry_mpi_t x, z, result; + if (!mpi_block_to_gcrypt(s->x_mem, n_bytes, &x)) { + goto error_ret; + } + if (!mpi_block_to_gcrypt(s->z_mem, n_bytes, &z)) { + goto error_x; + } + + /* Multiply */ + result = gcry_mpi_new(n_bytes * 8); + gcry_mpi_mul(result, x, z); + mpi_gcrypt_to_block(result, s->z_mem); + + /* Trigger an interrupt on completion */ + if (s->int_ena) { + qemu_set_irq(s->irq, 1); + } + + /* Clean up */ + gcry_mpi_release(result); + gcry_mpi_release(z); +error_x: + gcry_mpi_release(x); +error_ret: + return; +} + + +static void esp32c3_rsa_clean_mem(ESP32C3RsaState *s) +{ + memset(s->m_mem, 0, sizeof(s->m_mem)); + memset(s->x_mem, 0, sizeof(s->x_mem)); + memset(s->y_mem, 0, sizeof(s->y_mem)); + memset(s->z_mem, 0, sizeof(s->z_mem)); +} + +static uint64_t esp32c3_rsa_read(void *opaque, hwaddr addr, unsigned int size) +{ + ESP32C3RsaState *s = ESP32C3_RSA(opaque); + uint64_t r = 0; + + switch (addr) { + case A_RSA_MEM_M_BLOCK_BASE ... (A_RSA_MEM_M_BLOCK_BASE + ESP32C3_RSA_MEM_BLK_SIZE - 1): + r = s->m_mem[(addr - A_RSA_MEM_M_BLOCK_BASE) / sizeof(uint32_t)]; + break; + + case A_RSA_MEM_Z_BLOCK_BASE ... (A_RSA_MEM_Z_BLOCK_BASE + ESP32C3_RSA_MEM_BLK_SIZE - 1): + r = s->z_mem[(addr - A_RSA_MEM_Z_BLOCK_BASE) / sizeof(uint32_t)]; + break; + + case A_RSA_MEM_Y_BLOCK_BASE ... (A_RSA_MEM_Y_BLOCK_BASE + ESP32C3_RSA_MEM_BLK_SIZE - 1): + r = s->y_mem[(addr - A_RSA_MEM_Y_BLOCK_BASE) / sizeof(uint32_t)]; + break; + + case A_RSA_MEM_X_BLOCK_BASE ... (A_RSA_MEM_X_BLOCK_BASE + ESP32C3_RSA_MEM_BLK_SIZE - 1): + r = s->x_mem[(addr - A_RSA_MEM_X_BLOCK_BASE) / sizeof(uint32_t)]; + break; + + case A_RSA_M_PRIME_REG: + r = s->mprime_reg; + break; + + case A_RSA_MODE_REG: + r = s->mode_reg; + break; + + case A_RSA_CONSTANT_TIME_REG: + r = s->const_time_reg; + break; + + case A_RSA_SEARCH_ENABLE_REG: + r = s->search_ena_reg; + break; + + case A_RSA_SEARCH_POS_REG: + r = s->search_pos_reg; + break; + + case A_RSA_CLEAN_REG: + esp32c3_rsa_clean_mem(s); + r = 1; + break; + + case A_RSA_IDLE_REG: + /* Always Idle */ + r = 1; + break; + + case A_RSA_INTERRUPT_ENA_REG: + r = s->int_ena; + break; + + default: +#if RSA_WARNING + warn_report("[RSA] Unsupported read to register %08x\n", addr); +#endif + break; + + } + + return r; +} + + +static void esp32c3_rsa_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + ESP32C3RsaState *s = ESP32C3_RSA(opaque); + + switch (addr) { + + case A_RSA_MEM_M_BLOCK_BASE ... (A_RSA_MEM_M_BLOCK_BASE + ESP32C3_RSA_MEM_BLK_SIZE - 1): + s->m_mem[(addr - A_RSA_MEM_M_BLOCK_BASE) / sizeof(uint32_t)] = (uint32_t)value; + break; + + case A_RSA_MEM_Z_BLOCK_BASE ... (A_RSA_MEM_Z_BLOCK_BASE + ESP32C3_RSA_MEM_BLK_SIZE - 1): + s->z_mem[(addr - A_RSA_MEM_Z_BLOCK_BASE) / sizeof(uint32_t)] = (uint32_t)value; + break; + + case A_RSA_MEM_Y_BLOCK_BASE ... (A_RSA_MEM_Y_BLOCK_BASE + ESP32C3_RSA_MEM_BLK_SIZE - 1): + s->y_mem[(addr - A_RSA_MEM_Y_BLOCK_BASE) / sizeof(uint32_t)] = (uint32_t)value; + break; + + case A_RSA_MEM_X_BLOCK_BASE ... (A_RSA_MEM_X_BLOCK_BASE + ESP32C3_RSA_MEM_BLK_SIZE - 1): + s->x_mem[(addr - A_RSA_MEM_X_BLOCK_BASE) / sizeof(uint32_t)] = (uint32_t)value; + break; + + case A_RSA_M_PRIME_REG: + s->mprime_reg = value; + break; + + case A_RSA_MODE_REG: + s->mode_reg = FIELD_EX32(value, RSA_MODE_REG, RSA_MODE); + break; + + case A_RSA_CONSTANT_TIME_REG: + s->const_time_reg = FIELD_EX32(value, RSA_CONSTANT_TIME_REG, RSA_CONSTANT_TIME); + break; + + case A_RSA_SEARCH_ENABLE_REG: + s->search_ena_reg = FIELD_EX32(value, RSA_SEARCH_ENABLE_REG, RSA_SEARCH_ENABLE); + break; + + case A_RSA_SEARCH_POS_REG: + s->search_pos_reg = FIELD_EX32(value, RSA_SEARCH_POS_REG, RSA_SEARCH_POS); + break; + + case A_RSA_MODEXP_START_REG: + if (FIELD_EX32(value, RSA_MODEXP_START_REG, RSA_MODEXP_START)) { + esp32c3_rsa_exp_mod(s); + } + break; + + case A_RSA_MODMULT_START_REG: + if (FIELD_EX32(value, RSA_MODMULT_START_REG, RSA_MODMULT_START)) { + esp32c3_rsa_modmul_start(s); + } + break; + + case A_RSA_MULT_START_REG: + if (FIELD_EX32(value, RSA_MULT_START_REG, RSA_MULT_START)) { + esp32c3_rsa_mul_start(s); + } + break; + + case A_RSA_CLEAR_INTERRUPT_REG: + if (FIELD_EX32(value, RSA_CLEAR_INTERRUPT_REG, RSA_CLEAR_INTERRUPT)) { + qemu_irq_lower(s->irq); + } + break; + + case A_RSA_INTERRUPT_ENA_REG: + s->int_ena = FIELD_EX32(value, RSA_INTERRUPT_ENA_REG, RSA_INTERRUPT_ENA); + break; + + default: +#if RSA_WARNING + warn_report("[RSA] Unsupported write to register %08x\n", addr); +#endif + break; + } + +} + +static const MemoryRegionOps esp32c3_rsa_ops = { + .read = esp32c3_rsa_read, + .write = esp32c3_rsa_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32c3_rsa_reset(DeviceState *dev) +{ + ESP32C3RsaState *s = ESP32C3_RSA(dev); + + esp32c3_rsa_clean_mem(s); + + /* Clear any spurious interrupt */ + s->int_ena = 0; + qemu_irq_lower(s->irq); +} + +static void esp32c3_rsa_init(Object *obj) +{ + ESP32C3RsaState *s = ESP32C3_RSA(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32c3_rsa_ops, s, + TYPE_ESP32C3_RSA, ESP32C3_RSA_REGS_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + + sysbus_init_irq(sbd, &s->irq); +} + +static void esp32c3_rsa_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32c3_rsa_reset; +} + +static const TypeInfo esp32c3_rsa_info = { + .name = TYPE_ESP32C3_RSA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32C3RsaState), + .instance_init = esp32c3_rsa_init, + .class_init = esp32c3_rsa_class_init +}; + +static void esp32c3_rsa_register_types(void) +{ + type_register_static(&esp32c3_rsa_info); +} + +type_init(esp32c3_rsa_register_types) diff --git a/hw/misc/esp32c3_rtc_cntl.c b/hw/misc/esp32c3_rtc_cntl.c new file mode 100644 index 000000000000..0255d0fb821b --- /dev/null +++ b/hw/misc/esp32c3_rtc_cntl.c @@ -0,0 +1,141 @@ +/* + * ESP32-C3 RTC CNTL + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/misc/esp32c3_rtc_cntl.h" + + +#define RTCCNTL_DEBUG 0 +#define RTCCNTL_WARNING 0 + + +static uint64_t esp32c3_rtc_cntl_read(void* opaque, hwaddr addr, unsigned int size) +{ + ESP32C3RtcCntlState *s = ESP32C3_RTC_CNTL(opaque); + uint64_t r = 0; + + switch(addr) { + case A_RTC_CNTL_RTC_OPTIONS0: + r = s->options0; + break; + case A_RTC_CNTL_RTC_RESET_STATE: + r = ESP32C3_POWERON_RESET; + break; + case A_RTC_CNTL_RTC_STORE4: + /* XTAL frequency: 40MHz, must be in both upper and lower half-word */ + r = 0x00280028; + break; + default: +#if RTCCNTL_WARNING + /* Other registers are not supported yet */ + warn_report("[RTCCNTL] Unsupported read to %08lx\n", addr); +#endif + break; + } + + return r; +} + + +static void esp32c3_rtc_cntl_write(void* opaque, hwaddr addr, uint64_t value, unsigned int size) +{ + ESP32C3RtcCntlState *s = ESP32C3_RTC_CNTL(opaque); + const uint32_t c_value = value; + + switch(addr) { + case A_RTC_CNTL_RTC_OPTIONS0: + CLEAR_BIT(value, R_RTC_CNTL_RTC_OPTIONS0_SW_SYS_RST_SHIFT); + CLEAR_BIT(value, R_RTC_CNTL_RTC_OPTIONS0_SW_PROCPU_RST_SHIFT); + s->options0 = value; + /* Check if we have to reset the CPU/machine */ + if (FIELD_EX32(c_value, RTC_CNTL_RTC_OPTIONS0, SW_SYS_RST) || + FIELD_EX32(c_value, RTC_CNTL_RTC_OPTIONS0, SW_PROCPU_RST)) { + qemu_irq_raise(s->cpu_reset); + } + break; + default: +#if RTCCNTL_WARNING + /* Other registers are not supported yet */ + warn_report("[RTCCNTL] Unsupported write to %08lx (%08lx)\n", addr, value); +#endif + break; + } +} + + +static const MemoryRegionOps esp_rtc_cntl_ops = { + .read = esp32c3_rtc_cntl_read, + .write = esp32c3_rtc_cntl_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + + +static void esp32c3_rtc_cntl_reset(DeviceState *dev) +{ + ESP32C3RtcCntlState *s = ESP32C3_RTC_CNTL(dev); + s->options0 = 0; + qemu_irq_lower(s->cpu_reset); +} + + +static void esp32c3_rtc_cntl_realize(DeviceState *dev, Error **errp) +{ + ESP32C3RtcCntlState *s = ESP32C3_RTC_CNTL(dev); + esp32c3_rtc_cntl_reset(dev); + (void) s; +} + + +static void esp32c3_rtc_cntl_init(Object *obj) +{ + ESP32C3RtcCntlState *s = ESP32C3_RTC_CNTL(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp_rtc_cntl_ops, s, + TYPE_ESP32C3_RTC_CNTL, ESP32C3_RTC_CNTL_IO_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + + /* Initialize the GPIO that will notify the CPU to reset itself */ + qdev_init_gpio_out_named(DEVICE(s), &s->cpu_reset, ESP32C3_RTC_CPU_RESET_GPIO, 1); +} + + +static void esp32c3_rtc_cntl_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32c3_rtc_cntl_reset; + dc->realize = esp32c3_rtc_cntl_realize; +} + + +static const TypeInfo esp32c3_rtc_cntl_info = { + .name = TYPE_ESP32C3_RTC_CNTL, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32C3RtcCntlState), + .instance_init = esp32c3_rtc_cntl_init, + .class_init = esp32c3_rtc_cntl_class_init +}; + + +static void esp32c3_rtc_cntl_register_types(void) +{ + type_register_static(&esp32c3_rtc_cntl_info); +} + + +type_init(esp32c3_rtc_cntl_register_types) diff --git a/hw/misc/esp32c3_sha.c b/hw/misc/esp32c3_sha.c new file mode 100644 index 000000000000..f332694ac5f4 --- /dev/null +++ b/hw/misc/esp32c3_sha.c @@ -0,0 +1,321 @@ +/* + * ESP32 SHA accelerator + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/esp32c3_sha.h" +#include "hw/irq.h" + +#define SHA_WARNING 0 +#define SHA_DEBUG 0 + +#define SHA_OP_TYPE_MASK (1 << 0) +#define SHA_OP_DMA_MASK (1 << 1) + +typedef enum { + OP_START = 0, + OP_CONTINUE = 1, + OP_DMA_START = SHA_OP_DMA_MASK | OP_START, + OP_DMA_CONTINUE = SHA_OP_DMA_MASK | OP_CONTINUE, +} ESP32C3ShaOperation; + + +static ESP32C3HashAlg esp32c3_algs[] = { + [ESP32C3_SHA_1_MODE] = { + .init = (hash_init) sha1_init, + .compress = (hash_compress) sha1_compress, + .len = sizeof(struct sha1_state) + }, + [ESP32C3_SHA_224_MODE] = { + .init = (hash_init) sha224_init, + .compress = (hash_compress) sha224_compress, + .len = SHA224_HASH_SIZE + }, + [ESP32C3_SHA_256_MODE] = { + .init = (hash_init) sha256_init, + .compress = (hash_compress) sha256_compress, + .len = sizeof(struct sha256_state) + }, +}; + + +static void esp32c3_sha_continue_hash(ESP32C3ShaState *s) +{ + assert(s->mode <= ESP32C3_SHA_256_MODE); + ESP32C3HashAlg alg = esp32c3_algs[s->mode]; + + alg.compress(&s->context, (uint8_t*) s->message); + memcpy(s->hash, &s->context, alg.len); +} + + +static void esp32c3_sha_continue_dma(ESP32C3ShaState *s) +{ + assert(s->mode <= ESP32C3_SHA_256_MODE); + ESP32C3HashAlg alg = esp32c3_algs[s->mode]; + uint32_t gdma_out_idx = 0; + + assert(alg.compress); + + /* Number of blocks to process, each block is ESP32C3_MESSAGE_SIZE bytes big */ + const uint32_t blocks = s->block; + const uint32_t buf_size = blocks * ESP32C3_MESSAGE_SIZE; + + /* Get the GDMA channel connected to SHA module. + * Specify ESP32C3_GDMA_OUT_IDX since the data are going OUT of GDMA but IN our current component. */ + if ( !esp32c3_gdma_get_channel_periph(s->gdma, GDMA_SHA, ESP32C3_GDMA_OUT_IDX, &gdma_out_idx) ) + { + warn_report("[SHA] GDMA requested but no properly configured channel found"); + return; + } + + /* Allocate the buffer that will contain the data and get teh actual data */ + uint8_t* buffer = g_malloc(blocks * ESP32C3_MESSAGE_SIZE); + if (buffer == NULL) + { + error_report("[SHA] No more memory in host!"); + return; + } + + if ( !esp32c3_gdma_read_channel(s->gdma, gdma_out_idx, buffer, buf_size) ) { + warn_report("[SHA] Error reading from GDMA buffer"); + g_free(buffer); + } + + /* Perform the actual SHA operation on the whole buffer */ + for (uint32_t i = 0; i < blocks; i++) + { + alg.compress(&s->context, buffer + i * ESP32C3_MESSAGE_SIZE); + } + + memcpy(s->hash, &s->context, alg.len); + + g_free(buffer); + + /* Trigger an interrupt if enabled! */ + if (s->int_ena) { + qemu_irq_raise(s->irq); + } +} + + +static void esp32c3_sha_start(ESP32C3ShaState *s, ESP32C3ShaOperation op) +{ + ESP32C3HashAlg alg = esp32c3_algs[s->mode]; + assert(alg.init && alg.compress); + + if ((op & SHA_OP_TYPE_MASK) == OP_START) { + alg.init(&s->context); + } else { + /* Continue operation: initialize the context from the current hash. + * We don't have any accessor to do it so ... do it the "dirty" way */ + memcpy(&s->context, s->hash, alg.len); + } + + if ((op & SHA_OP_DMA_MASK) == SHA_OP_DMA_MASK) { + esp32c3_sha_continue_dma(s); + } else { + esp32c3_sha_continue_hash(s); + } +} + + +static uint64_t esp32c3_sha_read(void *opaque, hwaddr addr, unsigned int size) +{ + ESP32C3ShaState *s = ESP32C3_SHA(opaque); + hwaddr index = 0; + + uint64_t r = 0; + switch (addr) { + case A_SHA_MODE: + r = s->mode; + break; + case A_SHA_BUSY: + /* SHA driver is never busy as calculation happens synchronously */ + r = 0; + break; + case A_SHA_DATE: + /* Hardcode the version control register for now */ + r = 0x20190402; + break; + case A_SHA_H_MEM ... A_SHA_M_MEM - 1: + index = (addr - A_SHA_H_MEM) / sizeof(uint32_t); + r = bswap32(s->hash[index]); + break; + case A_SHA_M_MEM ... ESP32C3_SHA_REGS_SIZE - 1: + index = (addr - A_SHA_M_MEM) / sizeof(uint32_t); + r = s->message[index]; + break; + case A_SHA_DMA_BLOCK_NUM: + r = s->block; + break; + case A_SHA_IRQ_ENA: + r = s->int_ena ? 1 : 0; + break; + default: +#if SHA_WARNING + warn_report("[ESP32-C3] SHA DMA and IRQ unsupported for now, ignoring...\n"); +#endif + break; + } + +#if SHA_DEBUG + info_report("[ESP32-C3] SHA reading %08lx (%08lx)", addr, r); +#endif + + return r; +} + + +static void esp32c3_sha_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + ESP32C3ShaState *s = ESP32C3_SHA(opaque); + hwaddr index = 0; + +#if SHA_DEBUG + info_report("[ESP32-C3] SHA writing %08lx (%08lx)", addr, value); +#endif + + switch (addr) { + case A_SHA_MODE: + /* Make sure the value is always between 0 and 2 as the real hardware doesn't + * accept a value of 3. Choose SHA-1 by default in that case. */ + s->mode = (value & 0b11) % 3; + break; + + case A_SHA_START: + if (FIELD_EX32(value, SHA_START, START)) { + esp32c3_sha_start(s, OP_START); + } + break; + + case A_SHA_CONTINUE: + if (FIELD_EX32(value, SHA_CONTINUE, CONTINUE)) { + esp32c3_sha_start(s, OP_CONTINUE); + } + break; + + case A_SHA_H_MEM ... A_SHA_M_MEM - 1: + /* Only support word aligned access for the moment */ + if (size != sizeof(uint32_t)) { + error_report("[SHA] Only 32-bit word access supported at the moment"); + } + index = (addr - A_SHA_H_MEM) / sizeof(uint32_t); + s->hash[index] = bswap32((uint32_t) value); + break; + + case A_SHA_M_MEM ... ESP32C3_SHA_REGS_SIZE - 1: + index = (addr - A_SHA_M_MEM) / sizeof(uint32_t); + s->message[index] = (uint32_t) value; + break; + + case A_SHA_DMA_BLOCK_NUM: + s->block = FIELD_EX32(value, SHA_DMA_BLOCK_NUM, DMA_BLOCK_NUM); + break; + + case A_SHA_DMA_START: + if (FIELD_EX32(value, SHA_DMA_START, DMA_START)) { + esp32c3_sha_start(s, OP_DMA_START); + } + break; + + case A_SHA_DMA_CONTINUE: + if (FIELD_EX32(value, SHA_DMA_CONTINUE, DMA_CONTINUE)) { + esp32c3_sha_start(s, OP_DMA_CONTINUE); + } + break; + + case A_SHA_CLEAR_IRQ: + qemu_irq_lower(s->irq); + break; + + case A_SHA_IRQ_ENA: + s->int_ena = FIELD_EX32(value, SHA_IRQ_ENA, INTERRUPT_ENA) != 0; + break; + + default: +#if SHA_WARNING + /* Unsupported for now, do nothing */ + warn_report("[SHA] Unsupported write to %08lx\n", addr); +#endif + break; + } +} + +static const MemoryRegionOps esp32c3_sha_ops = { + .read = esp32c3_sha_read, + .write = esp32c3_sha_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + + +static void esp32c3_sha_reset(DeviceState *dev) +{ + ESP32C3ShaState *s = ESP32C3_SHA(dev); + memset(s->hash, 0, 8 * sizeof(uint32_t)); + memset(s->message, 0, ESP32C3_MESSAGE_WORDS * sizeof(uint32_t)); + + s->block = 0; + s->int_ena = 0; + qemu_irq_lower(s->irq); +} + + +static void esp32c3_sha_realize(DeviceState *dev, Error **errp) +{ + ESP32C3ShaState *s = ESP32C3_SHA(dev); + + /* Make sure GDMA was set of issue an error */ + if (s->gdma == NULL) { + error_report("[SHA] GDMA controller must be set!"); + } +} + + +static void esp32c3_sha_init(Object *obj) +{ + ESP32C3ShaState *s = ESP32C3_SHA(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32c3_sha_ops, s, + TYPE_ESP32C3_SHA, ESP32C3_SHA_REGS_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + + sysbus_init_irq(sbd, &s->irq); +} + +static void esp32_sha_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = esp32c3_sha_realize; + dc->reset = esp32c3_sha_reset; +} + +static const TypeInfo esp32c3_sha_info = { + .name = TYPE_ESP32C3_SHA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32C3ShaState), + .instance_init = esp32c3_sha_init, + .class_init = esp32_sha_class_init, +}; + +static void esp32c3_sha_register_types(void) +{ + type_register_static(&esp32c3_sha_info); +} + +type_init(esp32c3_sha_register_types) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index a40245ad44f2..2f197051f025 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -5,7 +5,7 @@ softmmu_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugexit.c')) softmmu_ss.add(when: 'CONFIG_ISA_TESTDEV', if_true: files('pc-testdev.c')) softmmu_ss.add(when: 'CONFIG_PCA9552', if_true: files('pca9552.c')) softmmu_ss.add(when: 'CONFIG_PCI_TESTDEV', if_true: files('pci-testdev.c')) -softmmu_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c')) +softmmu_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c', 'unimp-default.c')) softmmu_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c')) softmmu_ss.add(when: 'CONFIG_LED', if_true: files('led.c')) softmmu_ss.add(when: 'CONFIG_PVPANIC_COMMON', if_true: files('pvpanic.c')) @@ -125,6 +125,40 @@ softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-sysreg.c')) softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c')) +softmmu_ss.add(when: 'CONFIG_XTENSA_ESP32', if_true: files( + 'esp32_crosscore_int.c', + 'esp32_dport.c', + 'esp32_rng.c', + 'esp32_rtc_cntl.c', + 'esp32_sha.c', + 'esp32_aes.c', + 'esp32_ledc.c', + 'esp32_flash_enc.c', + 'esp32_unknown.c', + 'esp32_ana.c', + 'esp32_wifi.c', + 'esp32_wifi_ap.c', + 'esp32_wlan_packet.c', + 'esp32_phya.c', + 'esp32_fe.c', + 'ssi_psram.c' +)) +softmmu_ss.add(when: 'CONFIG_RISCV_ESP32C3', if_true: files( + 'esp32c3_cache.c', + 'esp32c3_sha.c', + 'esp32c3_jtag.c', + 'esp32c3_rtc_cntl.c' +)) + +if gcrypt.found() + softmmu_ss.add(when: [gcrypt, 'CONFIG_XTENSA_ESP32'], if_true: files( + 'esp32_rsa.c', + )) + softmmu_ss.add(when: [gcrypt, 'CONFIG_RISCV_ESP32C3'], if_true: files( + 'esp32c3_aes.c', + 'esp32c3_rsa.c' + )) +endif softmmu_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_ahb_apb_pnp.c')) diff --git a/hw/misc/ssi_psram.c b/hw/misc/ssi_psram.c new file mode 100644 index 000000000000..df8b24b9eaa8 --- /dev/null +++ b/hw/misc/ssi_psram.c @@ -0,0 +1,118 @@ +/* + * ESP-PSRAM basic emulation + * + * Copyright (c) 2021 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/irq.h" +#include "qemu/module.h" +#include "hw/qdev-properties.h" +#include "hw/misc/ssi_psram.h" + +#define CMD_READ_ID 0x9f +#define PSRAM_ID_MFG 0x0d +#define PSRAM_ID_KGD 0x5d + +static int get_eid_by_size(uint32_t size_mbytes) { + switch (size_mbytes) + { + case 2: + return 0x00; + case 4: + return 0x21; + case 8: + return 0x40; + default: + qemu_log_mask(LOG_UNIMP, "%s: PSRAM size %" PRIu32 "MB not implemented\n", + __func__, size_mbytes); + return 0; + } +} + +static uint32_t psram_read(SsiPsramState *s) +{ + uint32_t result = 0; + if (s->command == CMD_READ_ID) { + uint8_t read_id_response[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, PSRAM_ID_MFG, PSRAM_ID_KGD, + get_eid_by_size(s->size_mbytes), + 0xaa, 0xbb, 0xcc, 0xdd, 0xee + }; + int index = s->byte_count - s->dummy; + if (index < ARRAY_SIZE(read_id_response)) { + result = read_id_response[index]; + } + } + return result; +} + +static void psram_write(SsiPsramState *s, uint32_t value) +{ + if (s->byte_count == s->dummy) { + s->command = value; + } + s->byte_count++; +} + +static uint32_t psram_transfer(SSIPeripheral *dev, uint32_t value) +{ + SsiPsramState *s = SSI_PSRAM(dev); + psram_write(s, value); + return psram_read(s); +} + +static int psram_cs(SSIPeripheral *ss, bool select) +{ + SsiPsramState *s = SSI_PSRAM(ss); + + if (!select) { + s->byte_count = 0; + s->command = -1; + } + return 0; +} + +static void psram_realize(SSIPeripheral *ss, Error **errp) +{ + SsiPsramState *s = SSI_PSRAM(ss); + s->dummy = 1; +} + +static Property psram_properties[] = { + DEFINE_PROP_UINT32("size_mbytes", SsiPsramState, size_mbytes, 4), + DEFINE_PROP_END_OF_LIST(), +}; + + +static void psram_class_init(ObjectClass *klass, void *data) +{ + SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->transfer = psram_transfer; + k->set_cs = psram_cs; + k->cs_polarity = SSI_CS_LOW; + k->realize = psram_realize; + device_class_set_props(dc, psram_properties); +} + +static const TypeInfo psram_info = { + .name = TYPE_SSI_PSRAM, + .parent = TYPE_SSI_PERIPHERAL, + .instance_size = sizeof(SsiPsramState), + .class_init = psram_class_init +}; + +static void psram_register_types(void) +{ + type_register_static(&psram_info); +} + +type_init(psram_register_types) diff --git a/hw/misc/unimp-default.c b/hw/misc/unimp-default.c new file mode 100644 index 000000000000..8ca733d8e93f --- /dev/null +++ b/hw/misc/unimp-default.c @@ -0,0 +1,101 @@ +/* "Unimplemented" default device + * + * This is a dummy device which accepts and logs all accesses. + * It's useful for stubbing out regions of an SoC or board + * map which correspond to devices that have not yet been + * implemented. This is often sufficient to placate initial + * guest device driver probing such that the system will + * come up. + * + * Copyright Linaro Limited, 2017 + * Written by Peter Maydell + * Modified by redfast00 2023 + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/misc/unimp-default.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qapi/error.h" + +static uint64_t unimp_default_read(void *opaque, hwaddr offset, unsigned size) +{ + UnimplementedDefaultDeviceState *s = UNIMPLEMENTED_DEFAULT_DEVICE(opaque); + + qemu_log_mask(LOG_UNIMP, "%s: unimplemented default device read " + "(size %d, offset 0x%0*" HWADDR_PRIx ")\n", + s->name, size, s->offset_fmt_width, offset); + return s->default_value; +} + +static void unimp_default_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + UnimplementedDefaultDeviceState *s = UNIMPLEMENTED_DEFAULT_DEVICE(opaque); + + qemu_log_mask(LOG_UNIMP, "%s: unimplemented default device write " + "(size %d, offset 0x%0*" HWADDR_PRIx + ", value 0x%0*" PRIx64 ")\n", + s->name, size, s->offset_fmt_width, offset, size << 1, value); +} + +static const MemoryRegionOps unimp_default_ops = { + .read = unimp_default_read, + .write = unimp_default_write, + .impl.min_access_size = 1, + .impl.max_access_size = 8, + .valid.min_access_size = 1, + .valid.max_access_size = 8, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void unimp_default_realize(DeviceState *dev, Error **errp) +{ + UnimplementedDefaultDeviceState *s = UNIMPLEMENTED_DEFAULT_DEVICE(dev); + + if (s->size == 0) { + error_setg(errp, "property 'size' not specified or zero"); + return; + } + + if (s->name == NULL) { + error_setg(errp, "property 'name' not specified"); + return; + } + + s->offset_fmt_width = DIV_ROUND_UP(64 - clz64(s->size - 1), 4); + + memory_region_init_io(&s->iomem, OBJECT(s), &unimp_default_ops, s, + s->name, s->size); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); +} + +static Property unimp_default_properties[] = { + DEFINE_PROP_UINT64("size", UnimplementedDefaultDeviceState, size, 0), + DEFINE_PROP_STRING("name", UnimplementedDefaultDeviceState, name), + DEFINE_PROP_UINT64("default_value", UnimplementedDefaultDeviceState, default_value, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void unimp_default_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = unimp_default_realize; + device_class_set_props(dc, unimp_default_properties); +} + +static const TypeInfo unimp_default_info = { + .name = TYPE_UNIMPLEMENTED_DEFAULT_DEVICE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(UnimplementedDefaultDeviceState), + .class_init = unimp_default_class_init, +}; + +static void unimp_default_register_types(void) +{ + type_register_static(&unimp_default_info); +} + +type_init(unimp_default_register_types) diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c index 0b3dc3146e61..ff62b2667310 100644 --- a/hw/net/opencores_eth.c +++ b/hw/net/opencores_eth.c @@ -57,11 +57,20 @@ #define SET_REGFIELD(s, reg, field, data) \ SET_FIELD((s)->regs[reg], reg ## _ ## field, data) -/* PHY MII registers */ +/* DP83848C PHY MII registers. + * Registers 0x0-0xf are standard, 0x10-0x1d are vendor-specific. + */ enum { - MII_REG_MAX = 16, + MII_PHYSTS = 0x10, + MII_REG_MAX = 0x1e }; +/* DP83848C PHYSTS register bits */ +#define MII_PHYSTS_LINK (1 << 0) +#define MII_PHYSTS_SPEED (1 << 1) +#define MII_PHYSTS_DUPLEX (1 << 2) +#define MII_PHYSTS_ANC (1 << 4) /* auto-negotiation complete */ + typedef struct Mii { uint16_t regs[MII_REG_MAX]; bool link_ok; @@ -73,9 +82,12 @@ static void mii_set_link(Mii *s, bool link_ok) s->regs[MII_BMSR] |= MII_BMSR_LINK_ST; s->regs[MII_ANLPAR] |= MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD | MII_ANLPAR_10 | MII_ANLPAR_CSMACD; + s->regs[MII_PHYSTS] = MII_PHYSTS_LINK | MII_PHYSTS_SPEED | + MII_PHYSTS_DUPLEX | MII_PHYSTS_ANC; } else { s->regs[MII_BMSR] &= ~MII_BMSR_LINK_ST; s->regs[MII_ANLPAR] &= 0x01ff; + s->regs[MII_PHYSTS] = 0; } s->link_ok = link_ok; } @@ -114,6 +126,7 @@ static void mii_write_host(Mii *s, unsigned idx, uint16_t v) [MII_BMSR] = mii_ro, [MII_PHYID1] = mii_ro, [MII_PHYID2] = mii_ro, + [MII_PHYSTS] = mii_ro, }; if (idx < MII_REG_MAX) { @@ -128,8 +141,11 @@ static void mii_write_host(Mii *s, unsigned idx, uint16_t v) static uint16_t mii_read_host(Mii *s, unsigned idx) { - trace_open_eth_mii_read(idx, s->regs[idx]); - return s->regs[idx]; + if (idx < MII_REG_MAX) { + trace_open_eth_mii_read(idx, s->regs[idx]); + return s->regs[idx]; + } + return 0; } /* OpenCores Ethernet registers */ diff --git a/hw/nvram/esp32_efuse.c b/hw/nvram/esp32_efuse.c new file mode 100644 index 000000000000..41c033e9020c --- /dev/null +++ b/hw/nvram/esp32_efuse.c @@ -0,0 +1,307 @@ +/* + * ESP32 eFuse emulation + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "sysemu/sysemu.h" +#include "chardev/char-fe.h" +#include "hw/registerfields.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "hw/nvram/esp32_efuse.h" + +static void esp32_efuse_read_op(Esp32EfuseState *s); +static void esp32_efuse_program_op(Esp32EfuseState *s); +static void esp32_efuse_update_irq(Esp32EfuseState *s); +static void esp32_efuse_op_timer_start(Esp32EfuseState *s); + +static uint64_t esp32_efuse_read(void *opaque, hwaddr addr, unsigned int size) +{ + Esp32EfuseState *s = ESP32_EFUSE(opaque); + uint64_t r = 0; + int idx; + switch (addr) { + case A_EFUSE_BLK0_RDATA0 ... A_EFUSE_BLK0_WDATA0 - 4: + idx = (addr - A_EFUSE_BLK0_RDATA0) / 4; + r = s->efuse_rd.blk0[idx] & ~(s->efuse_rd_dis.blk0[idx]); + break; + case A_EFUSE_BLK0_WDATA0 ... A_EFUSE_BLK1_RDATA0 - 4: + r = s->efuse_wr.blk0[(addr - A_EFUSE_BLK0_WDATA0) / 4]; + break; + case A_EFUSE_BLK1_RDATA0 ... A_EFUSE_BLK2_RDATA0 - 4: + idx = (addr - A_EFUSE_BLK1_RDATA0) / 4; + r = s->efuse_rd.blk1[idx] & ~(s->efuse_rd_dis.blk1[idx]); + break; + case A_EFUSE_BLK2_RDATA0 ... A_EFUSE_BLK3_RDATA0 - 4: + idx = (addr - A_EFUSE_BLK2_RDATA0) / 4; + r = s->efuse_rd.blk2[idx] & ~(s->efuse_rd_dis.blk2[idx]); + break; + case A_EFUSE_BLK3_RDATA0 ... A_EFUSE_BLK1_WDATA0 - 4: + idx = (addr - A_EFUSE_BLK3_RDATA0) / 4; + r = s->efuse_rd.blk3[idx] & ~(s->efuse_rd_dis.blk3[idx]); + break; + case A_EFUSE_BLK1_WDATA0 ... A_EFUSE_BLK2_WDATA0 - 4: + r = s->efuse_wr.blk1[(addr - A_EFUSE_BLK1_WDATA0) / 4]; + break; + case A_EFUSE_BLK2_WDATA0 ... A_EFUSE_BLK3_WDATA0 - 4: + r = s->efuse_wr.blk2[(addr - A_EFUSE_BLK2_WDATA0) / 4]; + break; + case A_EFUSE_BLK3_WDATA0 ... A_EFUSE_CLK - 4: + r = s->efuse_wr.blk3[(addr - A_EFUSE_BLK3_WDATA0) / 4]; + break; + case A_EFUSE_CLK: + r = s->clk_reg; + break; + case A_EFUSE_CONF: + r = s->conf_reg; + break; + case A_EFUSE_CMD: + r = s->cmd_reg; + break; + case A_EFUSE_STATUS: + r = 0; + break; + case A_EFUSE_DAC_CONF: + r = s->dac_conf_reg; + break; + case A_EFUSE_INT_RAW: + r = s->int_raw_reg; + break; + case A_EFUSE_INT_ST: + r = s->int_st_reg; + break; + case A_EFUSE_INT_ENA: + r = s->int_ena_reg; + break; + case A_EFUSE_DEC_STATUS: + r = 0; + break; + case A_EFUSE_DATE: + r = 0x16042600; + } + return r; +} + +static void esp32_efuse_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + Esp32EfuseState *s = ESP32_EFUSE(opaque); + switch (addr) { + case A_EFUSE_CLK: + s->clk_reg = value; + break; + case A_EFUSE_CONF: + s->conf_reg = value; + break; + case A_EFUSE_CMD: + if ((value & EFUSE_READ) && s->conf_reg == EFUSE_READ_OP_CODE) { + esp32_efuse_read_op(s); + } + if ((value & EFUSE_PGM) && s->conf_reg == EFUSE_PGM_OP_CODE) { + esp32_efuse_program_op(s); + } + break; + case A_EFUSE_DAC_CONF: + s->dac_conf_reg = value; + break; + case A_EFUSE_INT_ENA: + s->int_ena_reg = value; + esp32_efuse_update_irq(s); + break; + case A_EFUSE_INT_CLR: + s->int_raw_reg &= ~value; + esp32_efuse_update_irq(s); + break; + case A_EFUSE_BLK0_WDATA0 ... A_EFUSE_BLK1_RDATA0 - 4: + s->efuse_wr.blk0[(addr - A_EFUSE_BLK0_WDATA0) / 4] = value; + break; + case A_EFUSE_BLK1_WDATA0 ... A_EFUSE_BLK2_WDATA0 - 4: + s->efuse_wr.blk1[(addr - A_EFUSE_BLK1_WDATA0) / 4] = value; + break; + case A_EFUSE_BLK2_WDATA0 ... A_EFUSE_BLK3_WDATA0 - 4: + s->efuse_wr.blk2[(addr - A_EFUSE_BLK2_WDATA0) / 4] = value; + break; + case A_EFUSE_BLK3_WDATA0 ... A_EFUSE_CLK - 4: + s->efuse_wr.blk3[(addr - A_EFUSE_BLK3_WDATA0) / 4] = value; + break; + } +} + +#define APPLY_DIS(rdwr_, ctrl_field_, dest_field_) \ + if (s->efuse_ ## rdwr_ .blk0_d0.ctrl_field_) { \ + memset(&s->efuse_ ## rdwr_ ## _dis.dest_field_, 0xff, sizeof(s->efuse_ ## rdwr_ ## _dis.dest_field_)); \ + } + +#define APPLY_DIS_FIELD(rdwr_, ctrl_field_, dest_field_) \ + if (s->efuse_ ## rdwr_ .blk0_d0.ctrl_field_) { \ + s->efuse_ ## rdwr_ ## _dis.dest_field_ = 0; \ + s->efuse_ ## rdwr_ ## _dis.dest_field_ -= 1; \ + } + + +static void esp32_efuse_read_op(Esp32EfuseState *s) +{ + s->cmd_reg = EFUSE_READ; + if (s->blk != NULL) { + int ret = blk_pread(s->blk, 0, sizeof(s->efuse_rd), &s->efuse_rd, 0); + if (ret < 0) { + error_report("%s: failed to read the block device (%d)", __func__, ret); + return; + } + } + + memset(&s->efuse_rd_dis, 0, sizeof(s->efuse_rd_dis)); + memset(&s->efuse_wr_dis, 0, sizeof(s->efuse_wr_dis)); + + APPLY_DIS(rd, rd_dis_blk1, blk1); + APPLY_DIS(rd, rd_dis_blk2, blk2); + APPLY_DIS(rd, rd_dis_blk3, blk3); + APPLY_DIS_FIELD(rd, rd_dis_blk0_partial, blk0_d5.flash_crypt_config); + APPLY_DIS_FIELD(rd, rd_dis_blk0_partial, blk0_d6.coding_scheme); + APPLY_DIS_FIELD(rd, rd_dis_blk0_partial, blk0_d6.key_status); + + APPLY_DIS(wr, wr_dis_blk1, blk1); + APPLY_DIS(wr, wr_dis_blk2, blk2); + APPLY_DIS(wr, wr_dis_blk3, blk3); + + /* Other wr_dis bits are not emulated, but can be handled here if necessary */ + + esp32_efuse_op_timer_start(s); + qemu_irq_pulse(s->efuse_update_gpio); +} + +static void esp32_efuse_program_op(Esp32EfuseState *s) +{ + s->cmd_reg = EFUSE_PGM; + + Esp32EfuseRegs result; + uint32_t* dst = (uint32_t*) &result; + uint32_t* rd = (uint32_t*) &s->efuse_rd; + uint32_t* wr = (uint32_t*) &s->efuse_wr; + uint32_t* wr_dis = (uint32_t*) &s->efuse_wr_dis; + for (int i = 0; i < sizeof(result) / sizeof(uint32_t); ++i) { + uint32_t wr_word = wr[i]; + uint32_t wr_dis_word = wr_dis[i]; + uint32_t rd_word = rd[i]; + dst[i] = (wr_word & (~wr_dis_word)) | rd_word; + } + + if (s->blk != NULL) { + int ret = blk_pwrite(s->blk, 0, sizeof(result), &result, 0); + if (ret < 0) { + error_report("%s: failed to write to block device (%d)", __func__, ret); + } + } + + esp32_efuse_op_timer_start(s); +} + +static void esp32_efuse_update_irq(Esp32EfuseState *s) +{ + s->int_st_reg = s->int_ena_reg & s->int_raw_reg; + int level = s->int_st_reg != 0; + qemu_set_irq(s->irq, level); +} + +static void esp32_efuse_op_timer_start(Esp32EfuseState *s) +{ + uint64_t ns_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + uint64_t interval_ns = 100000000; /* 10 ms, make this depend on EFUSE_CLK register */ + timer_mod_anticipate_ns(&s->op_timer, ns_now + interval_ns); +} + +static void esp32_efuse_timer_cb(void *opaque) +{ + Esp32EfuseState *s = ESP32_EFUSE(opaque); + uint32_t cmd = s->cmd_reg; + s->cmd_reg = 0; + s->int_raw_reg |= cmd; + esp32_efuse_update_irq(s); +} + +static const MemoryRegionOps esp32_efuse_ops = { + .read = esp32_efuse_read, + .write = esp32_efuse_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_efuse_reset(DeviceState *dev) +{ + Esp32EfuseState *s = ESP32_EFUSE(dev); + esp32_efuse_read_op(s); +} + +static void esp32_efuse_realize(DeviceState *dev, Error **errp) +{ + Esp32EfuseState *s = ESP32_EFUSE(dev); + if (s->blk != NULL) { + if (!blk_supports_write_perm(s->blk)) { + error_setg(errp, "%s: block device is not writeable", __func__); + return; + } + uint64_t perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; + int ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, NULL); + if (ret != 0) { + error_setg(errp, "%s: failed to set permission (%d)", __func__, ret); + return; + } + } +} + +static void esp32_efuse_init(Object *obj) +{ + Esp32EfuseState *s = ESP32_EFUSE(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_efuse_ops, s, + TYPE_ESP32_EFUSE, A_EFUSE_DATE + 4); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + + timer_init_ns(&s->op_timer, QEMU_CLOCK_VIRTUAL, esp32_efuse_timer_cb, s); + qdev_init_gpio_out_named(DEVICE(sbd), &s->efuse_update_gpio, ESP32_EFUSE_UPDATE_GPIO, 1); + + memset(&s->efuse_rd, 0, sizeof(s->efuse_rd)); + memset(&s->efuse_wr, 0, sizeof(s->efuse_wr)); +} + +static Property esp32_efuse_properties[] = { + DEFINE_PROP_DRIVE("drive", Esp32EfuseState, blk), + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32_efuse_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32_efuse_reset; + dc->realize = esp32_efuse_realize; + device_class_set_props(dc, esp32_efuse_properties); +} + +static const TypeInfo esp32_efuse_info = { + .name = TYPE_ESP32_EFUSE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32EfuseState), + .instance_init = esp32_efuse_init, + .class_init = esp32_efuse_class_init +}; + +static void esp32_efuse_register_types(void) +{ + type_register_static(&esp32_efuse_info); +} + +type_init(esp32_efuse_register_types) diff --git a/hw/nvram/esp32c3_efuse.c b/hw/nvram/esp32c3_efuse.c new file mode 100644 index 000000000000..31111b27a4b0 --- /dev/null +++ b/hw/nvram/esp32c3_efuse.c @@ -0,0 +1,522 @@ +/* + * ESP32-C3 eFuse emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "qapi/qmp/qdict.h" +#include "qemu/error-report.h" +#include "sysemu/sysemu.h" +#include "chardev/char-fe.h" +#include "hw/registerfields.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "hw/nvram/esp32c3_efuse.h" + + +#define EFUSE_DEBUG 0 + + +#define EFUSE_DEFAULT_FILENAME "qemu_efuses.bin" + +/** + * @brief Specify the delay, in us of a a write or read operation, this will only be used to simulate + * the delay the real efuses actually take on real hardware. + */ +#define EFUSE_OPERATION_DELAY_US 1000 + + +static uint64_t esp32c3_efuse_read(void *opaque, hwaddr addr, unsigned int size) +{ + ESP32C3EfuseState *s = ESP32C3_EFUSE(opaque); + uint8_t *content_8 = ((uint8_t*) &s->efuses) + addr; + uint16_t *content_16 = (uint16_t*) content_8; + uint32_t *content_32 = (uint32_t*) content_8; + + assert(addr < sizeof(s->efuses)); + + if (size == 1) { + return *content_8; + } else if (size == 2) { + return *content_16; + } else { + return *content_32; + } +} + +/** + * @brief Return the start offset in the ESP32C3EfuseRegs structure of the given block. + */ +static int esp32c3_offset_of_block(int block_num) +{ + const int offsets[] = { + ESP32C3_EFUSE_BLOCK0_ADDR, + ESP32C3_EFUSE_BLOCK1_ADDR, + ESP32C3_EFUSE_BLOCK2_ADDR, + ESP32C3_EFUSE_BLOCK3_ADDR, + ESP32C3_EFUSE_BLOCK4_ADDR, + ESP32C3_EFUSE_BLOCK5_ADDR, + ESP32C3_EFUSE_BLOCK6_ADDR, + ESP32C3_EFUSE_BLOCK7_ADDR, + ESP32C3_EFUSE_BLOCK8_ADDR, + ESP32C3_EFUSE_BLOCK9_ADDR, + ESP32C3_EFUSE_BLOCK10_ADDR, + }; + + assert(block_num < sizeof(offsets)/sizeof(int)); + return offsets[block_num]; +} + + +/** + * @brief Hide the protected efuses by overwriting them with 0s, this function shall be called after + * calling `esp32c3_efuse_read`. + */ +static void esp32c3_hide_protected_block(ESP32C3EfuseState *s) +{ + uint32_t rd_protection = s->efuses.rd_repeat_data0.rd_dis; + /* Only the BLOCK4 and upwards can be protected */ + int block_num = 4; + + while (rd_protection != 0) { + if (rd_protection & 1) { + /* Get the offset of the block in the ESP32C3EfuseRegs structure */ + const int offset = esp32c3_offset_of_block(block_num); + uint8_t* from = ((uint8_t*) &s->efuses) + offset; + /* The blocks that can be protected are all 32-byte long */ + memset(from, 0, 32); + } + rd_protection >>= 1; + block_num++; + } +} + + +/** + * @brief Load the efuses value from the block device (file) + */ +static void esp32c3_efuse_reload_from_blk(ESP32C3EfuseState *s) +{ + /* In theory, there are 4096 bits of efuses, in practice, the memory space allocated for + * efuses stops at &rd_repeat_err0. */ + const uint32_t size = offsetof(ESP32C3EfuseRegs, rd_repeat_err0) - offsetof(ESP32C3EfuseRegs, rd_wr_dis); + + /* Load the efuses from the block device file (or mirror) */ + if (s->blk) { + + /* Load the file content inside the structure, starting at efuse rd_wr_dis */ + const int ret = blk_pread(s->blk, 0, size, &s->efuses.rd_wr_dis, 0); + if (ret < 0) { + error_report("%s: failed to read the block device (%d)", __func__, ret); + } + + } else { + + assert(s->mirror); + memcpy(&s->efuses.rd_wr_dis, s->mirror, size); + + } +} + +/** + * @brief Get a mask of the protected bits for BLOCK0. + * A bit set to 1 marks a protected bit whereas a 0 marks an unprotected bit. + * + * @param wr_dis Write-disable register + * @param block0_mask Mask containing exactly ESP32C3_EFUSE_BLOCK0_WORDS words that will + * be filled with the masks described above. + */ +static void esp32c3_efuse_get_block0_protected_mask(uint32_t wr_dis, uint32_t *block0_mask) +{ + /* Define the constants that for each bit of wr_dis represent the word index they affect + * and the bits they protect */ + const struct { + uint32_t index; + uint32_t mask; + } protect_map[32] = { + [0] = { 1, 0x0000007f }, /* Bit 0: protects rd_repeat_data0 (index 1), rd_dis bits */ + /* Bit 1 unused */ + [2] = { 1, 0x0018df00 }, + [3] = { 2, 0x00030000 }, + [4] = { 2, 0x001c0000 }, + [5] = { 2, 0x00200000 }, + [6] = { 2, 0x00400000 }, + [7] = { 2, 0x00800000 }, + [8] = { 2, 0x0f000000 }, + [9] = { 2, 0xf0000000 }, + [10] = { 3, 0x0000000f }, + [11] = { 3, 0x000000f0 }, + [12] = { 3, 0x00000f00 }, + [13] = { 3, 0x0000f000 }, + /* Bit 14 unused */ + [15] = { 3, 0x00100000 }, + [16] = { 3, 0x00200000 }, + /* Bit 17 unused */ + [18] = { 4, 0x3fffe0f5 }, /* TODO: Make sure that bit 18 also protects EFUSE_FLASH_TPUW, omitted for now */ + [19] = { 4, 0x80000000 }, + /* bit 20 to 29 included don't affect BLOCK0 fields */ + [30] = { 1, 0x06000000 }, + [31] = { 1, 0x00070000 }, + }; + + memset(block0_mask, 0, ESP32C3_EFUSE_BLOCK0_WORDS * sizeof(uint32_t)); + + /* Go through all the bits of the write-disable mask and set the appropriate mask if the bit + * is set. Ignore bits from 20 to 29 included which are not about BLOCK 0 protection. */ + for (uint_fast32_t i = 0; i <= 31; i++) { + if ((i >= 20 && i <= 29) || (wr_dis & BIT(i)) == 0) { + continue; + } + /* Bit is set and within range */ + const uint32_t index = protect_map[i].index; + const uint32_t mask = protect_map[i].mask; + block0_mask[index] |= mask; + } +} + + +/** + * @brief Write a given efuses block to the block device (file) if not protected. + * Returns true if the block was flashed successfully, false else. + */ +static bool esp32c3_efuse_write_to_blk(ESP32C3EfuseState *s, const int block) +{ + const int size = esp32c3_efuse_block_size(block); + bool protected = false; + /* Mask of protected bit for each word of a BLOCK, only used when writing BLOCK0 */ + uint32_t block_mask[ESP32C3_EFUSE_PGM_DATA_COUNT] = { 0 }; + + /* If the block to protect is not BLOCK0 the check is rather simple */ + if (block != 0) { + assert(block <= 10); + /* BLOCK1 protection is bit 20, BLOCK2 protection is bit 21, etc... */ + const int offset = 19 + block; + /* If the bit is 1, protection is enabled, we cannot write */ + protected = (s->efuses.rd_wr_dis >> offset) & 1; + } else { + /* BLOCK0 protection is done on a bit granularity, so for each word that composes it + * get mask where 1 represents a protected bit, and 0 represents an unprotected bit */ + esp32c3_efuse_get_block0_protected_mask(s->efuses.rd_wr_dis, block_mask); + } + + if (!protected) { + /* Get the offset of the block in the ESP32C3EfuseRegs structure! + * Subtract the offset of the BLOCK0 to get the offset of our block in the + * binary file (blk). + * The offset in struct must be in 32-bit words */ + const uint32_t offset_in_struct = esp32c3_offset_of_block(block) / sizeof(uint32_t); + /* Offset in file must be in bytes */ + const uint32_t offset_in_file = esp32c3_offset_of_block(block) - esp32c3_offset_of_block(0); + + /* Generate the actual data to write to the file. Indeed, the programmed bits (1) shall + * NOT be programmed to 0 as on real hardware an efuse cannot be reverted. + * To do so, OR the content to burn with the existing content so that the 1s are never erased. */ + uint32_t *efuses = (uint32_t*) &s->efuses; + uint32_t real_data[ESP32C3_EFUSE_PGM_DATA_COUNT]; + + for (int i = 0; i < ESP32C3_EFUSE_PGM_DATA_COUNT; i++) { + /* Offset of pgm_data is 0, let's use efuses[i] to retrieve the data. + * efuses[i] represents the new value, efuses[offset_in_struct + i] represents the old value, + * block_mask represents the protection, with 1 marking a bit as protected. + * As such, the final result of an efuse value is: + * Y = old_value | (~block_mask & new_value) */ + real_data[i] = efuses[offset_in_struct + i] | (~block_mask[i] & efuses[i]); + } + + /* Write the new block data to the file (or RAM) */ + if (s->blk) { + + const int ret = blk_pwrite(s->blk, offset_in_file, size, real_data, 0); + if (ret < 0) { + error_report("%s: failed to write efuses to the block device (%d)", __func__, ret); + } + + } else { + + assert(s->mirror); + memcpy(s->mirror + offset_in_file, real_data, size); + + } + } + + /* Writing is a success if the block is not protected */ + return !protected; +} + + +/** + * @brief Callback called when the QEMU timer reaches its limit. + * It will set the raw status of the efuse component. If the requested operation was a read, + * it will perform the read from the binary file (blk) here. + */ +static void esp32c3_efuse_timer_cb(void *opaque) +{ + ESP32C3EfuseState *s = ESP32C3_EFUSE(opaque); + + /* To make sure the command register did not change between the moment the operation was scheduled + * and the moment the callback was triggered, restore its value to its original one. (mirror) + * In any case, it will be set to 0 at the end of this function */ + s->efuses.cmd.val = s->op_cmd_mirror; + + /* No need to check the opcode again */ + if (s->efuses.cmd.read_cmd) { + esp32c3_efuse_reload_from_blk(s); + esp32c3_hide_protected_block(s); + s->efuses.int_raw.read_done = 1; + } else { + assert(s->efuses.cmd.pgm_cmd); + s->efuses.int_raw.pgm_done = 1; + } + + /* In any case, reset the command register to show that the operation is finished */ + s->efuses.cmd.val = 0; + + /* Set the interrupt bits, if any is 1, trigger an interrupt */ + s->efuses.int_st.val = s->efuses.int_ena.val | s->efuses.int_raw.val; + if (s->efuses.int_st.val) { + qemu_irq_raise(s->irq); + } +} + + +/** + * @brief Start ESP32C3EfuseState's timer to simulate the efuse operation delay + */ +static void esp32c3_efuse_op_timer_start(ESP32C3EfuseState *s) +{ + const uint64_t ns_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + const uint64_t interval_ns = EFUSE_OPERATION_DELAY_US * 1000; + timer_mod_anticipate_ns(&s->op_timer, ns_now + interval_ns); +} + + +static void esp32c3_efuse_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + ESP32C3EfuseState *s = ESP32C3_EFUSE(opaque); + /* Address of the register to write if we consider efuses as an array of bytes */ + uint8_t *content_8 = ((uint8_t*) &s->efuses) + addr; + uint16_t *content_16 = (uint16_t*) content_8; + uint32_t *content_32 = (uint32_t*) content_8; + +#if EFUSE_DEBUG + info_report("[EFUSE] Writing to 0x%08lx = 0x%08lx (size: %d)\n", addr, value, size); +#endif + + /* Check if the programming cmd block is being written */ + if (addr == offsetof(ESP32C3EfuseRegs, cmd)) { + + s->efuses.cmd.val = (uint32_t) value; + + /* The command bit and the opcode will be check by the underlying function */ + if (esp32c3_efuse_is_read_cmd(s)) { + + /* Save the register value and schedule a timer to simulate real efuse loading delay, + * the copy will be done in the callback. */ + s->op_cmd_mirror = (uint32_t) value; + esp32c3_efuse_op_timer_start(s); + + } else if (esp32c3_efuse_is_write_cmd(s)) { + + const bool success = esp32c3_efuse_write_to_blk(s, s->efuses.cmd.blk_num); + + if (success) { + /* Same as for the read, schedule the timer and perform the actual transfer once it elapsed */ + s->op_cmd_mirror = (uint32_t) value; + esp32c3_efuse_op_timer_start(s); + } else { + s->efuses.cmd.val = 0; + s->op_cmd_mirror = 0; + } + } else { + s->efuses.cmd.val = 0; + } + + return; + } + + /* The first registers, up to rd_wr_dis excluded, can be written to freely */ + if (addr < offsetof(ESP32C3EfuseRegs, rd_wr_dis)) + { + if (size == 1) { + *content_8 = value & 0xff; + } else if (size == 2) { + *content_16 = value & 0xffff; + } else { + *content_32 = value; + } + + return; + } + + /* Treat the interrupt-related cases separately */ + switch (addr) { + case offsetof(ESP32C3EfuseRegs, int_clr): + /* Only clear the bits that are set to 1 in the value */ + s->efuses.int_raw.val &= ((~value) & 0b11); + break; + case offsetof(ESP32C3EfuseRegs, int_raw): + s->efuses.int_raw.val = 0; + break; + case offsetof(ESP32C3EfuseRegs, int_ena): + s->efuses.int_ena.val = value & 0b11; + break; + + /* For debugging purposes */ + case offsetof(ESP32C3EfuseRegs, dbg_erase_all): + { +#if EFUSE_DEBUG + info_report("[EFUSE] erasing all efuses!\n"); +#endif + uint32_t size = offsetof(ESP32C3EfuseRegs, rd_repeat_err0) - offsetof(ESP32C3EfuseRegs, rd_wr_dis); + memset(&s->efuses.rd_wr_dis, 0, size); + + if (s->blk) { + int ret = blk_pwrite(s->blk, 0, size, &s->efuses.rd_wr_dis, 0); + if (ret != 0) { + error_report("ERROR WRITING FILE: %d\n", ret); + exit(1); + } + } else { + + assert(s->mirror); + memset(s->mirror, 0, ESP32C3_EFUSE_BYTE_COUNT); + } + } + return; + + case offsetof(ESP32C3EfuseRegs, clk): + case offsetof(ESP32C3EfuseRegs, conf): + case offsetof(ESP32C3EfuseRegs, dac_conf): + case offsetof(ESP32C3EfuseRegs, rd_tim_conf): + case offsetof(ESP32C3EfuseRegs, wr_tim_conf1): + case offsetof(ESP32C3EfuseRegs, wr_tim_conf2): + /* Make sure we write these registers with a 32-bit access */ + assert(size >= 4); + *content_32 = value; + /* Fall-through */ + + /* The other registers are read-only */ + default: + return; + } + + /* Check if any interrupt needs to be triggered or, on the contrary, lowered */ + const uint32_t new_status = (s->efuses.int_ena.val | s->efuses.int_raw.val) & 0b11; + s->efuses.int_st.val = new_status; + + qemu_set_irq(s->irq, new_status ? 1 : 0); +} + + +static const MemoryRegionOps esp32c3_efuse_ops = { + .read = esp32c3_efuse_read, + .write = esp32c3_efuse_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + + +static void esp32c3_efuse_reset(DeviceState *dev) +{ + ESP32C3EfuseState *s = ESP32C3_EFUSE(dev); + timer_del(&s->op_timer); + qemu_irq_lower(s->irq); + esp32c3_efuse_reload_from_blk(s); + esp32c3_hide_protected_block(s); +} + +static void esp32c3_efuse_realize(DeviceState *dev, Error **errp) +{ + ESP32C3EfuseState *s = ESP32C3_EFUSE(dev); + const char* error_msg = NULL; + + /* If no file was given as efuses, create a temporary one (in RAM). */ + if (s->blk == NULL) { + s->mirror = g_malloc(ESP32C3_EFUSE_BYTE_COUNT); + if (s->mirror == NULL) { + error_msg = "failed to allocate memory for efuses"; + goto error; + } + + memset(s->mirror, 0, ESP32C3_EFUSE_BYTE_COUNT); + + /* Set the chip revision to v0.3 and write it to the file */ + s->efuses.rd_mac_spi_sys_3.wafer_version_minor_low = 3; + + /* No need to rewrite the all the efuses, rd_mac_spi_sys_3 is enough */ + const uint32_t offset = offsetof(ESP32C3EfuseRegs, rd_mac_spi_sys_3) - esp32c3_offset_of_block(0); + *((uint32_t*) (s->mirror + offset)) = s->efuses.rd_mac_spi_sys_3.val; + + } else { + /* A block was given as a parameter, open it in READ/WRITE */ + if (!blk_supports_write_perm(s->blk)) { + error_msg = "block device is not writeable or does not exist"; + goto error; + } + + uint64_t perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; + int ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, NULL); + if (ret != 0) { + error_msg = "failed to set permission"; + goto error; + } + + esp32c3_efuse_reset((DeviceState*) s); + } + + return; +error: + error_setg(errp, "%s: %s", __func__, error_msg); +} + +static void esp32c3_efuse_init(Object *obj) +{ + ESP32C3EfuseState *s = ESP32C3_EFUSE(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32c3_efuse_ops, s, + TYPE_ESP32C3_EFUSE, ESP32C3_EFUSE_IO_RANGE_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + + timer_init_ns(&s->op_timer, QEMU_CLOCK_VIRTUAL, esp32c3_efuse_timer_cb, s); +} + +static Property esp32c3_efuse_properties[] = { + DEFINE_PROP_DRIVE("drive", ESP32C3EfuseState, blk), + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32c3_efuse_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32c3_efuse_reset; + dc->realize = esp32c3_efuse_realize; + device_class_set_props(dc, esp32c3_efuse_properties); +} + +static const TypeInfo esp32c3_efuse_info = { + .name = TYPE_ESP32C3_EFUSE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32C3EfuseState), + .instance_init = esp32c3_efuse_init, + .class_init = esp32c3_efuse_class_init +}; + +static void esp32c3_efuse_register_types(void) +{ + type_register_static(&esp32c3_efuse_info); +} + +type_init(esp32c3_efuse_register_types) diff --git a/hw/nvram/meson.build b/hw/nvram/meson.build index f5ee9f6b88c4..3a3c1e11192a 100644 --- a/hw/nvram/meson.build +++ b/hw/nvram/meson.build @@ -11,6 +11,8 @@ softmmu_ss.add(when: 'CONFIG_AT24C', if_true: files('eeprom_at24c.c')) softmmu_ss.add(when: 'CONFIG_MAC_NVRAM', if_true: files('mac_nvram.c')) softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_otp.c')) softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_nvm.c')) +softmmu_ss.add(when: 'CONFIG_XTENSA_ESP32', if_true: files('esp32_efuse.c')) +softmmu_ss.add(when: 'CONFIG_RISCV_ESP32C3', if_true: files('esp32c3_efuse.c')) softmmu_ss.add(when: 'CONFIG_XLNX_EFUSE_CRC', if_true: files('xlnx-efuse-crc.c')) softmmu_ss.add(when: 'CONFIG_XLNX_EFUSE', if_true: files('xlnx-efuse.c')) softmmu_ss.add(when: 'CONFIG_XLNX_EFUSE_VERSAL', if_true: files( diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 6528ebfa3a3b..39bd3adb6234 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -84,3 +84,7 @@ config SPIKE select HTIF select RISCV_ACLINT select SIFIVE_PLIC + +config RISCV_ESP32C3 + bool + select UNIMP diff --git a/hw/riscv/esp32c3.c b/hw/riscv/esp32c3.c new file mode 100644 index 000000000000..e43b4ba63a05 --- /dev/null +++ b/hw/riscv/esp32c3.c @@ -0,0 +1,556 @@ +/* + * ESP32-C3 SoC and machine + * + * Copyright (c) 2019-2022 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "hw/qdev-properties.h" +#include "qemu/units.h" +#include "qemu/datadir.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/riscv/riscv_hart.h" +#include "target/riscv/esp_cpu.h" +#include "hw/riscv/boot.h" +#include "hw/riscv/numa.h" +#include "sysemu/device_tree.h" +#include "sysemu/sysemu.h" +#include "sysemu/kvm.h" +#include "sysemu/runstate.h" +#include "sysemu/reset.h" +#include "hw/misc/esp32c3_reg.h" +#include "hw/misc/esp32c3_rtc_cntl.h" +#include "hw/misc/esp32c3_cache.h" +#include "hw/char/esp32c3_uart.h" +#include "hw/gpio/esp32c3_gpio.h" +#include "hw/nvram/esp32c3_efuse.h" +#include "hw/riscv/esp32c3_clk.h" +#include "hw/riscv/esp32c3_intmatrix.h" +#include "hw/misc/esp32c3_sha.h" +#include "hw/timer/esp32c3_timg.h" +#include "hw/timer/esp32c3_systimer.h" +#include "hw/ssi/esp32c3_spi.h" +#include "hw/misc/esp32c3_rtc_cntl.h" +#include "hw/misc/esp32c3_aes.h" +#include "hw/misc/esp32c3_rsa.h" +#include "hw/misc/esp32c3_jtag.h" +#include "hw/dma/esp32c3_gdma.h" + +#define ESP32C3_IO_WARNING 0 + +#define ESP32C3_RESET_ADDRESS 0x40000000 + +#define MB (1024*1024) + + +/* Define a new "class" which derivates from "MachineState" */ +struct Esp32C3MachineState { + MachineState parent; + + /* Attributes specific to our class */ + EspRISCVCPU soc; + BusState periph_bus; + MemoryRegion iomem; + + qemu_irq cpu_reset; + + ESP32C3IntMatrixState intmatrix; + ESP32C3UARTState uart[ESP32C3_UART_COUNT]; + ESP32C3GPIOState gpio; + ESP32C3CacheState cache; + ESP32C3EfuseState efuse; + ESP32C3ClockState clock; + ESP32C3GdmaState gdma; + ESP32C3AesState aes; + ESP32C3ShaState sha; + ESP32C3RsaState rsa; + ESP32C3TimgState timg[2]; + ESP32C3SysTimerState systimer; + ESP32C3SpiState spi1; + ESP32C3RtcCntlState rtccntl; + ESP32C3UsbJtagState jtag; +}; + +/* Temporary macro for generating a random value from register SYSCON_RND_DATA_REG */ +#define A_SYSCON_RND_DATA_REG 0x0B0 + +/* Temporary macro to mark the CPU as in non-debugging mode */ +#define A_ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG 0x098 + +/* Create a macro which defines the name of our new machine class */ +#define TYPE_ESP32C3_MACHINE MACHINE_TYPE_NAME("esp32c3") + +/* This will create a macro ESP32_MACHINE, which can be used to check and cast a generic MachineClass + * to the specific class we defined above: Esp32C3MachineState. */ +OBJECT_DECLARE_SIMPLE_TYPE(Esp32C3MachineState, ESP32C3_MACHINE) + +/* Memory entries for ESP32-C3 */ +enum MemoryRegions { + ESP32C3_MEMREGION_IROM, + ESP32C3_MEMREGION_DROM, + ESP32C3_MEMREGION_DRAM, + ESP32C3_MEMREGION_IRAM, + ESP32C3_MEMREGION_RTCFAST, + ESP32C3_MEMREGION_DCACHE, + ESP32C3_MEMREGION_ICACHE, +}; + +#define ESP32C3_INTERNAL_SRAM0_SIZE (16*1024) + +static const struct MemmapEntry { + hwaddr base; + hwaddr size; +} esp32c3_memmap[] = { + [ESP32C3_MEMREGION_IROM] = { 0x40000000, 0x60000 }, + [ESP32C3_MEMREGION_DROM] = { 0x3ff00000, 0x20000 }, + [ESP32C3_MEMREGION_DRAM] = { 0x3fc80000, 0x60000 }, + /* Merge SRAM0 and SRAM1 into a single entry */ + [ESP32C3_MEMREGION_IRAM] = { 0x4037c000, 0x60000 + ESP32C3_INTERNAL_SRAM0_SIZE }, + [ESP32C3_MEMREGION_RTCFAST] = { 0x50000000, 0x2000 }, + [ESP32C3_MEMREGION_DCACHE] = { 0x3c000000, 0x800000 }, + [ESP32C3_MEMREGION_ICACHE] = { 0x42000000, 0x800000 }, +}; + + +static bool addr_in_range(hwaddr addr, hwaddr start, hwaddr end) +{ + return addr >= start && addr < end; +} + +static uint64_t esp32c3_io_read(void *opaque, hwaddr addr, unsigned int size) +{ + if (addr_in_range(addr + ESP32C3_IO_START_ADDR, DR_REG_RTC_I2C_BASE, DR_REG_RTC_I2C_BASE + 0x100)) { + return (uint32_t) 0xffffff; + } else if (addr + ESP32C3_IO_START_ADDR == DR_REG_SYSCON_BASE + A_SYSCON_RND_DATA_REG) { + /* Return a random 32-bit value */ + static bool init = false; + if (!init) { + srand(time(NULL)); + init = true; + } + return rand(); + } else if (addr + ESP32C3_IO_START_ADDR == DR_REG_ASSIST_DEBUG_BASE + A_ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG) { + return 0; + } else { +#if ESP32C3_IO_WARNING + warn_report("[ESP32-C3] Unsupported read to $%08lx\n", ESP32C3_IO_START_ADDR + addr); +#endif + } + return 0; +} + +static void esp32c3_io_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size) +{ +#if ESP32C3_IO_WARNING + warn_report("[ESP32-C3] Unsupported write $%08lx = %08lx\n", ESP32C3_IO_START_ADDR + addr, value); +#endif +} + + +/* Define operations for I/OS */ +static const MemoryRegionOps esp32c3_io_ops = { + .read = esp32c3_io_read, + .write = esp32c3_io_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + + +static void esp32c3_cpu_reset(void* opaque, int n, int level) +{ + Esp32C3MachineState *s = ESP32C3_MACHINE(qdev_get_machine()); + + if (level) { + + /* Reset the devices */ + device_cold_reset(DEVICE(&s->intmatrix)); + device_cold_reset(DEVICE(&s->gpio)); + device_cold_reset(DEVICE(&s->cache)); + device_cold_reset(DEVICE(&s->efuse)); + device_cold_reset(DEVICE(&s->clock)); + device_cold_reset(DEVICE(&s->gdma)); + device_cold_reset(DEVICE(&s->aes)); + device_cold_reset(DEVICE(&s->sha)); + device_cold_reset(DEVICE(&s->rsa)); + device_cold_reset(DEVICE(&s->systimer)); + device_cold_reset(DEVICE(&s->spi1)); + device_cold_reset(DEVICE(&s->rtccntl)); + device_cold_reset(DEVICE(&s->jtag)); + + for (int i = 0; i < 2; i++) { + device_cold_reset(DEVICE(&s->timg[i])); + } + + for (int i = 0; i < ESP32C3_UART_COUNT; i++) { + device_cold_reset(DEVICE(&s->uart[i])); + } + + ShutdownCause cause = SHUTDOWN_CAUSE_GUEST_RESET; + qemu_system_reset_request(cause); + } +} + +static void esp32c3_init_spi_flash(Esp32C3MachineState *ms, BlockBackend* blk) +{ + DeviceState *spi_master = DEVICE(&ms->spi1); + BusState* spi_bus = qdev_get_child_bus(spi_master, "spi"); + const char* flash_model = NULL; + int64_t image_size = blk_getlength(blk); + + switch (image_size) { + case 2 * MB: + flash_model = "w25x16"; + break; + case 4 * MB: + flash_model = "gd25q32"; + break; + case 8 * MB: + flash_model = "gd25q64"; + break; + case 16 * MB: + flash_model = "is25lp128"; + break; + default: + error_report("Drive size error: only 2, 4, 8, and 16MB images are supported"); + return; + } + + /* Create the SPI flash model */ + DeviceState *flash_dev = qdev_new(flash_model); + qdev_prop_set_drive(flash_dev, "drive", blk); + + /* Realize the SPI flash, its "drive" (blk) property must already be set! */ + qdev_realize(flash_dev, spi_bus, &error_fatal); + qdev_connect_gpio_out_named(spi_master, SSI_GPIO_CS, 0, + qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0)); +} + + +static void esp32c3_machine_init(MachineState *machine) +{ + /* First thing to do is to check if a drive format and a file ahve been passed through the command line. + * In fact, we will emulate the SPI flash if `if=mtd` was given. To know this, we will need to use the + * Global API's function `driver_get`. */ + BlockBackend* blk = NULL; + DriveInfo *dinfo = drive_get(IF_MTD, 0, 0); + if (dinfo) { + /* MTD was given! We need to initialize and emulate SPI flash */ + qemu_log("Adding SPI flash device\n"); + blk = blk_by_legacy_dinfo(dinfo); + } else { + qemu_log("Not initializing SPI Flash\n"); + } + + /* Re-use the macro that checks and casts any generic/parent class to the real child instance */ + Esp32C3MachineState *ms = ESP32C3_MACHINE(machine); + + /* Initialize SoC */ + object_initialize_child(OBJECT(ms), "soc", &ms->soc, TYPE_ESP_RISCV_CPU); + qdev_prop_set_uint64(DEVICE(&ms->soc), "resetvec", ESP32C3_RESET_ADDRESS); + + /* Initialize the peripheral bus */ + qbus_init(&ms->periph_bus, sizeof(ms->periph_bus), + TYPE_SYSTEM_BUS, DEVICE(ms), "esp32c3-periph-bus"); + + /* Initialize the memory mapping */ + const struct MemmapEntry *memmap = esp32c3_memmap; + MemoryRegion *sys_mem = get_system_memory(); + + /* Initialize the IROM */ + MemoryRegion *irom = g_new(MemoryRegion, 1); + memory_region_init_rom(irom, NULL, "esp32c3.irom", memmap[ESP32C3_MEMREGION_IROM].size, &error_fatal); + memory_region_add_subregion(sys_mem, memmap[ESP32C3_MEMREGION_IROM].base, irom); + + /* Initialize the DROM as an alias to IROM. */ + MemoryRegion *drom = g_new(MemoryRegion, 1); + const hwaddr offset_in_orig = 0x40000; + memory_region_init_alias(drom, NULL, "esp32c3.drom", irom, offset_in_orig, memmap[ESP32C3_MEMREGION_DROM].size); + memory_region_add_subregion(sys_mem, memmap[ESP32C3_MEMREGION_DROM].base, drom); + + /* Initialize the IRAM */ + MemoryRegion *iram = g_new(MemoryRegion, 1); + memory_region_init_ram(iram, NULL, "esp32c3.iram", memmap[ESP32C3_MEMREGION_IRAM].size, &error_fatal); + memory_region_add_subregion(sys_mem, memmap[ESP32C3_MEMREGION_IRAM].base, iram); + + /* Initialize DRAM as an alias to IRAM (not including Internal SRAM 0) */ + MemoryRegion *dram = g_new(MemoryRegion, 1); + /* DRAM mirrors IRAM for SRAM 1, skip the SRAM 0 area */ + memory_region_init_alias(dram, NULL, "esp32c3.dram", iram, + ESP32C3_INTERNAL_SRAM0_SIZE, memmap[ESP32C3_MEMREGION_DRAM].size); + memory_region_add_subregion(sys_mem, memmap[ESP32C3_MEMREGION_DRAM].base, dram); + + /* Initialize RTC Fast Memory as regular RAM */ + MemoryRegion *rtcram = g_new(MemoryRegion, 1); + memory_region_init_ram(rtcram, NULL, "esp32c3.rtcram", memmap[ESP32C3_MEMREGION_RTCFAST].size, &error_fatal); + memory_region_add_subregion(sys_mem, memmap[ESP32C3_MEMREGION_RTCFAST].base, rtcram); + + qdev_realize(DEVICE(&ms->soc), NULL, &error_fatal); + + memory_region_init_io(&ms->iomem, OBJECT(&ms->soc), &esp32c3_io_ops, + NULL, "esp32c3.iomem", 0xd1000); + memory_region_add_subregion(sys_mem, ESP32C3_IO_START_ADDR, &ms->iomem); + + + /* Initialize the I/O of the CPU */ + qdev_init_gpio_in_named(DEVICE(&ms->soc), esp32c3_cpu_reset, ESP32C3_RTC_CPU_RESET_GPIO, 1); + + /* Initialize the I/O peripherals */ + for (int i = 0; i < ESP32C3_UART_COUNT; ++i) { + char name[16]; + snprintf(name, sizeof(name), "uart%d", i); + object_initialize_child(OBJECT(machine), name, &ms->uart[i], TYPE_ESP32C3_UART); + + snprintf(name, sizeof(name), "serial%d", i); + object_property_add_alias(OBJECT(machine), name, OBJECT(&ms->uart[i]), "chardev"); + qdev_prop_set_chr(DEVICE(&ms->uart[i]), "chardev", serial_hd(i)); + } + + object_initialize_child(OBJECT(machine), "intmatrix", &ms->intmatrix, TYPE_ESP32C3_INTMATRIX); + object_initialize_child(OBJECT(machine), "gpio", &ms->gpio, TYPE_ESP32C3_GPIO); + object_initialize_child(OBJECT(machine), "extmem", &ms->cache, TYPE_ESP32C3_CACHE); + object_initialize_child(OBJECT(machine), "efuse", &ms->efuse, TYPE_ESP32C3_EFUSE); + object_initialize_child(OBJECT(machine), "clock", &ms->clock, TYPE_ESP32C3_CLOCK); + object_initialize_child(OBJECT(machine), "sha", &ms->sha, TYPE_ESP32C3_SHA); + object_initialize_child(OBJECT(machine), "aes", &ms->aes, TYPE_ESP32C3_AES); + object_initialize_child(OBJECT(machine), "gdma", &ms->gdma, TYPE_ESP32C3_GDMA); + object_initialize_child(OBJECT(machine), "rsa", &ms->rsa, TYPE_ESP32C3_RSA); + object_initialize_child(OBJECT(machine), "timg0", &ms->timg[0], TYPE_ESP32C3_TIMG); + object_initialize_child(OBJECT(machine), "timg1", &ms->timg[1], TYPE_ESP32C3_TIMG); + object_initialize_child(OBJECT(machine), "systimer", &ms->systimer, TYPE_ESP32C3_SYSTIMER); + object_initialize_child(OBJECT(machine), "spi1", &ms->spi1, TYPE_ESP32C3_SPI); + object_initialize_child(OBJECT(machine), "rtccntl", &ms->rtccntl, TYPE_ESP32C3_RTC_CNTL); + object_initialize_child(OBJECT(machine), "jtag", &ms->jtag, TYPE_ESP32C3_JTAG); + + /* Realize all the I/O peripherals we depend on */ + + /* Interrupt matrix realization */ + { + /* Store the current Machine CPU in the interrupt matrix */ + object_property_set_link(OBJECT(&ms->intmatrix), "cpu", OBJECT(&ms->soc), &error_abort); + qdev_realize(DEVICE(&ms->intmatrix), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->intmatrix), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_INTERRUPT_BASE, mr, 0); + + /* Connect all the interrupt matrix 31 output lines to the CPU 31 input IRQ lines. + * The lines are indexed starting at 1. + */ + for (int i = 0; i <= ESP32C3_CPU_INT_COUNT; i++) { + qemu_irq cpu_input = qdev_get_gpio_in_named(DEVICE(&ms->soc), ESP_CPU_IRQ_LINES_NAME, i); + qdev_connect_gpio_out_named(DEVICE(&ms->intmatrix), ESP32C3_INT_MATRIX_OUTPUT_NAME, i, cpu_input); + } + } + + DeviceState* intmatrix_dev = DEVICE(&ms->intmatrix); + + /* USB Serial JTAG realization */ + { + qdev_realize(DEVICE(&ms->jtag), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->jtag), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_USB_SERIAL_JTAG_BASE, mr, 0); + } + + /* RTC CNTL realization */ + { + qdev_realize(DEVICE(&ms->rtccntl), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->rtccntl), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_RTCCNTL_BASE, mr, 0); + qdev_connect_gpio_out_named(DEVICE(&ms->rtccntl), ESP32C3_RTC_CPU_RESET_GPIO, 0, + qdev_get_gpio_in_named(DEVICE(&ms->soc), ESP32C3_RTC_CPU_RESET_GPIO, 0)); + } + + /* SPI1 controller (SPI Flash) */ + { + qdev_realize(DEVICE(&ms->spi1), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->spi1), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_SPI1_BASE, mr, 0); + esp32c3_init_spi_flash(ms, blk); + } + + for (int i = 0; i < ESP32C3_UART_COUNT; ++i) { + const hwaddr uart_base[] = { DR_REG_UART_BASE, DR_REG_UART1_BASE }; + qdev_realize(DEVICE(&ms->uart[i]), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->uart[i]), 0); + memory_region_add_subregion_overlap(sys_mem, uart_base[i], mr, 0); + sysbus_connect_irq(SYS_BUS_DEVICE(&ms->uart[i]), 0, + qdev_get_gpio_in(intmatrix_dev, ETS_UART0_INTR_SOURCE + i)); + } + + /* GPIO realization */ + { + qdev_realize(DEVICE(&ms->gpio), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->gpio), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_GPIO_BASE, mr, 0); + } + + /* (Extmem) Cache realization */ + { + if (blk) { + ms->cache.flash_blk = blk; + } + qdev_realize(DEVICE(&ms->cache), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->cache), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_EXTMEM_BASE, mr, 0); + + memory_region_add_subregion_overlap(sys_mem, ms->cache.dcache_base, &ms->cache.dcache, 0); + memory_region_add_subregion_overlap(sys_mem, ms->cache.icache_base, &ms->cache.icache, 0); + } + + /* eFuses realization */ + { + qdev_realize(DEVICE(&ms->efuse), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->efuse), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_EFUSE_BASE, mr, 0); + sysbus_connect_irq(SYS_BUS_DEVICE(&ms->efuse), 0, + qdev_get_gpio_in(intmatrix_dev, ETS_EFUSE_INTR_SOURCE)); + } + + /* System clock realization */ + { + qdev_realize(DEVICE(&ms->clock), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->clock), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_SYSTEM_BASE, mr, 0); + /* Connect the IRQ lines to the interrupt matrix */ + for (int i = 0; i < ESP32C3_SYSTEM_CPU_INTR_COUNT; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&ms->clock), i, + qdev_get_gpio_in(intmatrix_dev, ETS_FROM_CPU_INTR0_SOURCE + i)); + } + } + + /* Timer Groups realization */ + { + qdev_realize(DEVICE(&ms->timg[0]), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->timg[0]), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_TIMERGROUP0_BASE, mr, 0); + /* Connect the T0 interrupt line to the interrupt matrix */ + qdev_connect_gpio_out_named(DEVICE(&ms->timg[0]), ESP32C3_T0_IRQ_INTERRUPT, 0, + qdev_get_gpio_in(intmatrix_dev, ETS_TG0_T0_LEVEL_INTR_SOURCE)); + /* Connect the Watchdog interrupt line to the interrupt matrix */ + qdev_connect_gpio_out_named(DEVICE(&ms->timg[0]), ESP32C3_WDT_IRQ_INTERRUPT, 0, + qdev_get_gpio_in(intmatrix_dev, ETS_TG0_WDT_LEVEL_INTR_SOURCE)); + /* Connect the Watchdog reset request */ + qdev_connect_gpio_out_named(DEVICE(&ms->timg[0]), ESP32C3_WDT_IRQ_RESET, 0, + qdev_get_gpio_in_named(DEVICE(&ms->soc), ESP32C3_RTC_CPU_RESET_GPIO, 0)); + + } + { + qdev_realize(DEVICE(&ms->timg[1]), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->timg[1]), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_TIMERGROUP1_BASE, mr, 0); + /* Connect the T0 interrupt line to the interrupt matrix */ + qdev_connect_gpio_out_named(DEVICE(&ms->timg[1]), ESP32C3_T0_IRQ_INTERRUPT, 0, + qdev_get_gpio_in(intmatrix_dev, ETS_TG1_T0_LEVEL_INTR_SOURCE)); + qdev_connect_gpio_out_named(DEVICE(&ms->timg[1]), ESP32C3_WDT_IRQ_INTERRUPT, 0, + qdev_get_gpio_in(intmatrix_dev, ETS_TG1_WDT_LEVEL_INTR_SOURCE)); + qdev_connect_gpio_out_named(DEVICE(&ms->timg[1]), ESP32C3_WDT_IRQ_RESET, 0, + qdev_get_gpio_in_named(DEVICE(&ms->soc), ESP32C3_RTC_CPU_RESET_GPIO, 0)); + } + + /* System timer */ + { + qdev_realize(DEVICE(&ms->systimer), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->systimer), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_SYSTIMER_BASE, mr, 0); + for (int i = 0; i < ESP32C3_SYSTIMER_IRQ_COUNT; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&ms->systimer), i, + qdev_get_gpio_in(intmatrix_dev, ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE + i)); + } + } + + /* GDMA Realization */ + { + object_property_set_link(OBJECT(&ms->gdma), "soc_mr", OBJECT(dram), &error_abort); + qdev_realize(DEVICE(&ms->gdma), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->gdma), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_GDMA_BASE, mr, 0); + /* Connect the IRQs to the Interrupt Matrix */ + for (int i = 0; i < ESP32C3_GDMA_CHANNEL_COUNT; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&ms->gdma), i, + qdev_get_gpio_in(intmatrix_dev, ETS_DMA_CH0_INTR_SOURCE + i)); + } + + } + + /* SHA realization */ + { + ms->sha.gdma = &ms->gdma; + qdev_realize(DEVICE(&ms->sha), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->sha), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_SHA_BASE, mr, 0); + sysbus_connect_irq(SYS_BUS_DEVICE(&ms->sha), 0, + qdev_get_gpio_in(intmatrix_dev, ETS_SHA_INTR_SOURCE)); + } + + /* AES realization */ + { + ms->aes.gdma = &ms->gdma; + qdev_realize(DEVICE(&ms->aes), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->aes), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_AES_BASE, mr, 0); + sysbus_connect_irq(SYS_BUS_DEVICE(&ms->aes), 0, + qdev_get_gpio_in(intmatrix_dev, ETS_AES_INTR_SOURCE)); + } + + /* RSA realization */ + { + qdev_realize(DEVICE(&ms->rsa), &ms->periph_bus, &error_fatal); + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&ms->rsa), 0); + memory_region_add_subregion_overlap(sys_mem, DR_REG_RSA_BASE, mr, 0); + sysbus_connect_irq(SYS_BUS_DEVICE(&ms->rsa), 0, + qdev_get_gpio_in(intmatrix_dev, ETS_RSA_INTR_SOURCE)); + } + + /* Open and load the "bios", which is the ROM binary, also named "first stage bootloader" */ + char *rom_binary = qemu_find_file(QEMU_FILE_TYPE_BIOS, "esp32c3-rom.bin"); + if (rom_binary == NULL) { + error_report("Error: -bios argument not set, and ROM code binary not found (1)"); + exit(1); + } + + /* Load ROM file at the reset address */ + int size = load_image_targphys_as(rom_binary, ESP32C3_RESET_ADDRESS, 0x60000, CPU(&ms->soc)->as); + if (size < 0) { + error_report("Error: could not load ROM binary '%s'", rom_binary); + exit(1); + } + + g_free(rom_binary); +} + + +/* Initialize machine type */ +static void esp32c3_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + mc->desc = "Espressif ESP32-C3 machine"; + mc->default_cpu_type = TYPE_ESP_RISCV_CPU; + mc->init = esp32c3_machine_init; + mc->max_cpus = 1; + mc->default_cpus = 1; + // 0x4f600 + mc->default_ram_size = 400 * 1024; +} + +/* Create a new type of machine ("child class") */ +static const TypeInfo esp32c3_info = { + .name = TYPE_ESP32C3_MACHINE, + /* Specify the parent class, i.e. the class we derivate from */ + .parent = TYPE_MACHINE, + /* Real size in bytes of our machine instance */ + .instance_size = sizeof(Esp32C3MachineState), + /* Override the init function to one we defined above */ + .class_init = esp32c3_machine_class_init, +}; + +static void esp32c3_machine_type_init(void) +{ + type_register_static(&esp32c3_info); +} + +type_init(esp32c3_machine_type_init); diff --git a/hw/riscv/esp32c3_clk.c b/hw/riscv/esp32c3_clk.c new file mode 100644 index 000000000000..25e51f941e60 --- /dev/null +++ b/hw/riscv/esp32c3_clk.c @@ -0,0 +1,159 @@ +/* + * ESP32-C3 CPU Clock and Reset emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/riscv/esp32c3_clk.h" + +#define CLOCK_DEBUG 0 +#define CLOCK_WARNING 0 + +static uint32_t esp32c3_read_cpu_intr(ESP32C3ClockState *s, uint32_t index) +{ + return (s->levels >> index) & 1; +} + + +static void esp32c3_write_cpu_intr(ESP32C3ClockState *s, uint32_t index, uint32_t value) +{ + const uint32_t field = FIELD_EX32(value, SYSTEM_CPU_INTR_FROM_CPU_0, CPU_INTR_FROM_CPU_0); + if (field) { + s->levels |= BIT(index); + qemu_set_irq(s->irqs[index], 1); + } else { + s->levels &= ~BIT(index); + qemu_set_irq(s->irqs[index], 0); + } +} + + +static uint64_t esp32c3_clock_read(void *opaque, hwaddr addr, unsigned int size) +{ + ESP32C3ClockState *s = ESP32C3_CLOCK(opaque); + uint64_t r = 0; + + switch(addr) { + case A_SYSTEM_CPU_PER_CONF: + r = s->cpuperconf; + break; + case A_SYSTEM_SYSCLK_CONF: + r = s->sysclk; + break; + case A_SYSTEM_CPU_INTR_FROM_CPU_0: + case A_SYSTEM_CPU_INTR_FROM_CPU_1: + case A_SYSTEM_CPU_INTR_FROM_CPU_2: + case A_SYSTEM_CPU_INTR_FROM_CPU_3: + r = esp32c3_read_cpu_intr(s, (addr - A_SYSTEM_CPU_INTR_FROM_CPU_0) / sizeof(uint32_t)); + break; + default: +#if CLOCK_WARNING + warn_report("[CLOCK] Unsupported read from %08lx\n", addr); +#endif + break; + } + return r; +} + +static void esp32c3_clock_write(void *opaque, hwaddr addr, uint64_t value, + unsigned int size) +{ + ESP32C3ClockState *s = ESP32C3_CLOCK(opaque); + + switch(addr) { + case A_SYSTEM_CPU_INTR_FROM_CPU_0: + case A_SYSTEM_CPU_INTR_FROM_CPU_1: + case A_SYSTEM_CPU_INTR_FROM_CPU_2: + case A_SYSTEM_CPU_INTR_FROM_CPU_3: + esp32c3_write_cpu_intr(s, (addr - A_SYSTEM_CPU_INTR_FROM_CPU_0) / sizeof(uint32_t), value); + break; + default: +#if CLOCK_WARNING + warn_report("[CLOCK] Unsupported write to %08lx (%08lx)\n", addr, value); +#endif + break; + } +} + +static const MemoryRegionOps esp32c3_clock_ops = { + .read = esp32c3_clock_read, + .write = esp32c3_clock_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32c3_clock_reset(DeviceState *dev) +{ + ESP32C3ClockState *s = ESP32C3_CLOCK(dev); + /* On board reset, set the proper clocks and dividers */ + s->sysclk = ( 1 << R_SYSTEM_SYSCLK_CONF_PRE_DIV_CNT_SHIFT) | + (ESP32C3_CLK_SEL_PLL << R_SYSTEM_SYSCLK_CONF_SOC_CLK_SEL_SHIFT) | + (40 << R_SYSTEM_SYSCLK_CONF_CLK_XTAL_FREQ_SHIFT) | + ( 1 << R_SYSTEM_SYSCLK_CONF_CLK_DIV_EN_SHIFT); + + /* Divider for PLL clock and APB frequency */ + s->cpuperconf = (ESP32C3_PERIOD_SEL_80 << R_SYSTEM_CPU_PER_CONF_CPUPERIOD_SEL_SHIFT) | + (ESP32C3_FREQ_SEL_PLL_480 << R_SYSTEM_CPU_PER_CONF_PLL_FREQ_SEL_SHIFT); + + /* Initialize the IRQs */ + s->levels = 0; + for (int i = 0 ; i < ESP32C3_SYSTEM_CPU_INTR_COUNT; i++) { + qemu_irq_lower(s->irqs[i]); + } +} + +static void esp32c3_clock_realize(DeviceState *dev, Error **errp) +{ + /* Initialize the registers */ + esp32c3_clock_reset(dev); +} + +static void esp32c3_clock_init(Object *obj) +{ + ESP32C3ClockState *s = ESP32C3_CLOCK(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32c3_clock_ops, s, + TYPE_ESP32C3_CLOCK, A_SYSTEM_COMB_PVT_ERR_HVT_SITE3 + sizeof(uint32_t)); + sysbus_init_mmio(sbd, &s->iomem); + + /* Initialize the output IRQ lines used to manually trigger interrupts */ + for (uint64_t i = 0; i < ESP32C3_SYSTEM_CPU_INTR_COUNT; i++) { + sysbus_init_irq(sbd, &s->irqs[i]); + } +} + +static void esp32c3_clock_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32c3_clock_reset; + dc->realize = esp32c3_clock_realize; +} + +static const TypeInfo esp32c3_cache_info = { + .name = TYPE_ESP32C3_CLOCK, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32C3ClockState), + .instance_init = esp32c3_clock_init, + .class_init = esp32c3_clock_class_init +}; + +static void esp32c3_cache_register_types(void) +{ + type_register_static(&esp32c3_cache_info); +} + +type_init(esp32c3_cache_register_types) diff --git a/hw/riscv/esp32c3_intmatrix.c b/hw/riscv/esp32c3_intmatrix.c new file mode 100644 index 000000000000..1a2c890e38e1 --- /dev/null +++ b/hw/riscv/esp32c3_intmatrix.c @@ -0,0 +1,408 @@ +/* + * ESP32-C3 Interrupt Matrix + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/queue.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/riscv/riscv_hart.h" +#include "hw/riscv/esp32c3_intmatrix.h" +#include "esp_cpu.h" + +#define INTMATRIX_DEBUG 0 +#define INTMATRIX_WARNING 0 + +#define BIT_SET(reg, bit) ((reg) & BIT(bit)) +#define CLEAR_BIT(reg, bit) do { (reg) &= ~BIT(bit); } while(0) +#define SET_BIT(reg, bit) do { (reg) |= BIT(bit); } while(0) + + +extern long esp32c3_get_real_int_cause(CPUState *cs); + + +/* Because the interrupts are asynchronous, there is a small chance that multiple interrupts + * are triggered at the same time, overlapping the first one. Use a FIFO structure to store + * all the events. This may not be required once the custom RISC-V core is implemented (which + * would serialize the incoming IRQs). */ +#define ESP32C3_IRQ_FIFO_LENGTH 8 + + +static void esp32c3_do_int(ESP32C3IntMatrixState *s, int line) +{ + qemu_irq_pulse(s->out_irqs[line]); +} + + +static int esp32c3_get_output_line_level(ESP32C3IntMatrixState *s, int line) +{ + int level_shared = 0; + + for (int i = 0; level_shared == 0 && i < ESP32C3_INT_MATRIX_INPUTS; i++) { + const uint_fast8_t mapped = s->irq_map[i]; + if (mapped == line && (s->irq_levels & BIT(i))) + { + level_shared |= 1; + } + } + + return level_shared; +} + +/** + * Try to clear the given interrupt from the pending bitmap. + * If the signal is shared with other interrupt sources, make sure all of them are low (0) + * before clearing the pending IRQ from the bitmap. + */ +static void esp32c3_intmatrix_clear_pending(ESP32C3IntMatrixState *s, int line) +{ + /* Check if another GPIO IRQ is sharing the same output line. They must all be low before + * clearing the pending bit. This is due to the fact that output lines + * can be shared on the ESP32-C3 */ + const int output_level = esp32c3_get_output_line_level(s, line); + if (!output_level) { + /* The output interrupt line is 0, so we can clear the pending flag */ + CLEAR_BIT(s->irq_pending, line); + } +} + + +/** + * Check if an interrupt can be triggered. + * This is the case if the interrupt matrix hasn't notified the CPU yet that an interrupt is incoming. + * Because interrupt handling is asynchronous in QEMU, if an interrupt occurs right now, MIE will not be set + * until the current TB (guest compiled block) terminates and CPU checks for the current interrupts. + * The problem is that, here, if another interrupt of a valid priority occurs before the current TB finished + * its execution (MIE still set), the interrupt will be accepted, put inside our IRQ FIFO and popped + * when the guest is still handling the previous interrupt which is not a valid state! + * As interrupts on the ESP32-C3 occur as soon as the interrupt line is raised, MIE is directly reset, forbidding + * any other interrupt to occur. The interrupt handler will raise the priority and re-enable it. + * Thus, make sure our FIFO is before triggering an interrupt, and ignore MIE flag which is meaningless. + */ +static bool esp32c3_intmatrix_can_trigger(ESP32C3IntMatrixState *s) +{ + return esp_cpu_accept_interrupts(s->cpu); +} + + +static void esp32c3_intmatrix_irq_handler(void *opaque, int n, int level) +{ + ESP32C3IntMatrixState *s = ESP32C3_INTMATRIX(opaque); + + /* Update the level mirror */ + assert(n <= ESP32C3_INT_MATRIX_INPUTS); + + /* Make sure level is 0 or 1 */ + level = level ? 1 : 0; + + /* Save the former level of the pin */ + const int former_level = BIT_SET(s->irq_levels, n) ? 1 : 0; + + if (level) { + SET_BIT(s->irq_levels, n); + } else { + CLEAR_BIT(s->irq_levels, n); + } + + const int line = s->irq_map[n]; + + /* If the line is not enable, don't do anything special, the level has been recorded already. + * Don't do anything if the line is at the same level as before */ + if ((s->irq_enabled & BIT(line)) == 0 || former_level == level) { + return; + } + + /* If the new level is high, check that the priority is equal or bigger than the threshold. + * If that's the case, we can execute the interrupt, else, mark it as pending. */ + if (level == 1) { +#if INTMATRIX_DEBUG + info_report("\x1b[31m[INTMATRIX] IRQ %d priority set to %d, CPU threshold %d \x1b[0m\n", + line, s->irq_prio[line], s->irq_thres); +#endif + + if (s->irq_prio[line] >= s->irq_thres && esp32c3_intmatrix_can_trigger(s)) { + esp32c3_do_int(s, line); + } else { + SET_BIT(s->irq_pending, line); + } + } else if (BIT_SET(s->irq_pending, line)) { + esp32c3_intmatrix_clear_pending(s, line); + } +} + + +static void esp32c3_intmatrix_irq_prio_changed(ESP32C3IntMatrixState* s, uint32_t line, uint8_t priority) +{ + const bool accept = esp32c3_intmatrix_can_trigger(s); + + if (accept && priority >= s->irq_thres && BIT_SET(s->irq_pending, line)) { + /* No need to clear the pending bit here. As soon as the interrupt source will be ACK by the + * software, its level will be update, as well as its pending state. */ + esp32c3_do_int(s, line); + } +} + + +static void esp32c3_intmatrix_core_prio_changed(ESP32C3IntMatrixState* s, uint64_t new_cpu_priority) +{ + uint64_t pending = s->irq_pending; + const bool accept = esp32c3_intmatrix_can_trigger(s); + + if (pending && accept) { + int64_t priority = -1; + uint_fast32_t line = 0; + + /* Clear all the interrupts that have a lower priority than the new CPU threshold */ + for (uint_fast32_t i = 1; i <= ESP32C3_CPU_INT_COUNT; i++) { + + const uint64_t line_prio = s->irq_prio[i]; + if (line_prio < new_cpu_priority) { + CLEAR_BIT(pending, i); + } + } + + /* No high level interrupt pending? */ + if (pending == 0) { + return; + } + + /* Look for the highest priority pending interrupt */ + for (uint_fast32_t i = 1; i <= ESP32C3_CPU_INT_COUNT; i++) { + const int64_t line_prio = (int64_t) s->irq_prio[i]; + if (BIT_SET(pending, i) && line_prio > priority) { + priority = line_prio; + line = i; + } + } + + /* Make sure a line was selected with its new priority */ + assert(line != 0); + assert(priority >= new_cpu_priority); + /* No need to clear the pending bit here. As soon as the interrupt source will be ACK by the + * software, its level will be update, as well as its pending state. */ + esp32c3_do_int(s, line); + } +} + + +/** + * This function is called when the status (enabled/disabled) of a line has just been changed. + * It will update the pending IRQ map. + */ +static void esp32c3_intmatrix_irq_status_changed(ESP32C3IntMatrixState* s, uint32_t line, int enabled) +{ + const bool accept = esp32c3_intmatrix_can_trigger(s); + + if (!enabled) { + + /* IRQ has just been disabled, if any interrupt is pending, clear it */ + CLEAR_BIT(s->irq_pending, line); + + } else if (esp32c3_get_output_line_level(s, line)) { + + /* IRQ has just been re-enabled, we have to check if any interrupt source is mapped to it, and + * if that's the case, check if their level is high, as we would need to potentially trigger an + * interrupt. */ + SET_BIT(s->irq_pending, line); + + if (accept) { + /* If the CPU can accept interrupt, trigger an interrupt now */ + esp32c3_do_int(s, line); + } + } +} + + +static uint64_t esp32c3_intmatrix_read(void* opaque, hwaddr addr, unsigned int size) +{ + ESP32C3IntMatrixState *s = ESP32C3_INTMATRIX(opaque); + const uint32_t index = addr / sizeof(uint32_t); + uint32_t r = 0; + + if (index <= 61) { + r = s->irq_map[index]; + } else if (index >= ESP32C3_INTMATRIX_IO_PRIO_START && index < ESP32C3_INTMATRIX_IO_PRIO_END) { + const uint32_t line = index - ESP32C3_INTMATRIX_IO_PRIO_START; + r = s->irq_prio[line]; + } else if (index == ESP32C3_INTMATRIX_IO_THRESH_REG) { + r = s->irq_thres; + } else if (index == ESP32C3_INTMATRIX_IO_ENABLE_REG) { + r = s->irq_enabled; + } else if (index == ESP32C3_INTMATRIX_IO_TYPE_REG) { + r = 0; + } else { +#if INTMATRIX_WARNING + /* Other registers are not supported yet */ + warn_report("[INTMATRIX] Unsupported read to %08lx\n", addr); +#endif + } + + return r; +} + +static void esp32c3_intmatrix_write(void* opaque, hwaddr addr, uint64_t value, unsigned int size) +{ + ESP32C3IntMatrixState *s = ESP32C3_INTMATRIX(opaque); + + const uint32_t index = addr / sizeof(uint32_t); + + if (index <= 61) { + + s->irq_map[index] = (value & 0x1f); +#if INTMATRIX_DEBUG + info_report("\x1b[31m[INTMATRIX] Mapping interrupt %d to CPU line %d\x1b[0m\n", index, s->irq_map[index]); +#endif + + } else if (index >= ESP32C3_INTMATRIX_IO_PRIO_START && index < ESP32C3_INTMATRIX_IO_PRIO_END) { + + const uint8_t priority = value & 0xf; + const uint32_t line = (index - ESP32C3_INTMATRIX_IO_PRIO_START) + 1; + s->irq_prio[line] = priority; +#if INTMATRIX_DEBUG + info_report("\x1b[31m[INTMATRIX] Priority of line %d set to %d\x1b[0m\n", line, priority); +#endif + /* Check if the new priority interrupts the CPU */ + esp32c3_intmatrix_irq_prio_changed(s, line, priority); + + } else if (index == ESP32C3_INTMATRIX_IO_THRESH_REG) { + + const uint8_t priority = value & 0xf; + + /** + * If the new priority is the same as the former one, nothing must be done. + * Else, this could result in an infinite loop. Let's say we have an interrupt source + * that is mapped to a CPU line, its threshold is 2, the CPU threshold is 3. + * When the interrupt source is asserted, no interrupt is triggered, because the line's + * priority is lower than the threshold but the its pending bit is set . + * As soon as the threshold is lowered to 2 or 1, the interrupt will be triggered because + * its pending bit is set. + * NOTE THAT THE PENDING BIT IS STILL SET BECAUSE THE SOURCE IS STILL ASSERTED! + * As such, if the CPU sets the threshold to the same value, the function + * `esp32c3_intmatrix_core_prio_changed` called below would re-schedule the same interrupt. + */ + if (priority != s->irq_thres) { + s->irq_thres = priority; +#if INTMATRIX_DEBUG + info_report("\x1b[31m[INTMATRIX] Setting CPU IRQ threshold to %d\x1b[0m\n", priority); +#endif + esp32c3_intmatrix_core_prio_changed(s, priority); + } + + } else if (index == ESP32C3_INTMATRIX_IO_ENABLE_REG) { + /* Check if any bit has changed status */ + uint64_t prev = s->irq_enabled; + s->irq_enabled = value; + /* Check which interrupt/bit changed + * Interrupts starts at 1, so we need to count up to ESP32C3_CPU_INT_COUNT */ + for (int i = 0; i <= ESP32C3_CPU_INT_COUNT; i++) { + const int new_st = value & BIT(i); + const int old_st = prev & BIT(i); + if (new_st != old_st) { + esp32c3_intmatrix_irq_status_changed(s, i, new_st ? 1 : 0); + } + } + } else if (index == ESP32C3_INTMATRIX_IO_TYPE_REG) { + if (value != 0) { +#if INTMATRIX_WARNING + warn_report("[INTMATRIX] Edge-triggered interrupts not supported\n"); +#endif + } + } else { +#if INTMATRIX_WARNING + /* Other registers are not supported yet */ + warn_report("[INTMATRIX] Unsupported write to %08lx (%08lx)\n", addr, value); +#endif + } +} + +static const MemoryRegionOps esp_intmatrix_ops = { + .read = esp32c3_intmatrix_read, + .write = esp32c3_intmatrix_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + + +static void esp32c3_intmatrix_reset(DeviceState *dev) +{ + ESP32C3IntMatrixState *s = ESP32C3_INTMATRIX(dev); + RISCVCPU *cpu = &s->cpu->parent_obj; + + memset(s->irq_map, 0, sizeof(s->irq_map)); + memset(s->irq_prio, 0, sizeof(s->irq_prio)); + s->irq_thres = 0; + s->irq_pending = 0; + s->irq_levels = 0; + s->irq_trigger = 0; + s->irq_enabled = 0; + for (int i = 0; i <= ESP32C3_CPU_INT_COUNT; i++) { + qemu_irq_lower(s->out_irqs[i]); + } + + /* Force the CPU to allow all interrupts */ + riscv_csr_write(&cpu->env, CSR_MIE, BIT(12) - 1); +} + + +static void esp32c3_intmatrix_realize(DeviceState *dev, Error **errp) +{ + esp32c3_intmatrix_reset(dev); +} + + +static void esp32c3_intmatrix_init(Object *obj) +{ + ESP32C3IntMatrixState *s = ESP32C3_INTMATRIX(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp_intmatrix_ops, s, + TYPE_ESP32C3_INTMATRIX, ESP32C3_INTMATRIX_IO_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + + qdev_init_gpio_in(DEVICE(s), esp32c3_intmatrix_irq_handler, ESP32C3_INT_MATRIX_INPUTS); + qdev_init_gpio_out_named(DEVICE(s), s->out_irqs, ESP32C3_INT_MATRIX_OUTPUT_NAME, ESP32C3_CPU_INT_COUNT + 1); +} + + +static Property esp32c3_intmatrix_properties[] = { + DEFINE_PROP_LINK("cpu", ESP32C3IntMatrixState, cpu, TYPE_ESP_RISCV_CPU, EspRISCVCPU*), + DEFINE_PROP_END_OF_LIST(), +}; + + +static void esp32c3_intmatrix_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32c3_intmatrix_reset; + dc->realize = esp32c3_intmatrix_realize; + device_class_set_props(dc, esp32c3_intmatrix_properties); +} + + +static const TypeInfo esp32c3_intmatrix_info = { + .name = TYPE_ESP32C3_INTMATRIX, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32C3IntMatrixState), + .instance_init = esp32c3_intmatrix_init, + .class_init = esp32c3_intmatrix_class_init +}; + + +static void esp32c3_intmatrix_register_types(void) +{ + type_register_static(&esp32c3_intmatrix_info); +} + + +type_init(esp32c3_intmatrix_register_types) diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index 2f7ee81be3ca..be0858cf1391 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -10,5 +10,6 @@ riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c')) riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c')) riscv_ss.add(when: 'CONFIG_MICROCHIP_PFSOC', if_true: files('microchip_pfsoc.c')) riscv_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c')) +riscv_ss.add(when: 'CONFIG_RISCV_ESP32C3', if_true: files('esp32c3.c', 'esp32c3_clk.c', 'esp32c3_intmatrix.c')) hw_arch += {'riscv': riscv_ss} diff --git a/hw/sd/Kconfig b/hw/sd/Kconfig index 633b9afec915..684e6bd6e797 100644 --- a/hw/sd/Kconfig +++ b/hw/sd/Kconfig @@ -23,3 +23,7 @@ config SDHCI_PCI config CADENCE_SDHCI bool select SDHCI + +config DWC_SDMMC + bool + select SD diff --git a/hw/sd/dwc_sdmmc.c b/hw/sd/dwc_sdmmc.c new file mode 100644 index 000000000000..9b9cf1a7726a --- /dev/null +++ b/hw/sd/dwc_sdmmc.c @@ -0,0 +1,586 @@ +/* + * Designware SD/MMC controller emulation + * + * Copyright (c) 2021 Espressif Systems (Shanghai) Co. Ltd. + * + * Based on Allwinner SD Host controller emulation (allwinner-sdhost.c), + * Copyright (C) 2019 Niek Linnenbank + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "hw/sd/dwc_sdmmc.h" +#include "qapi/error.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/units.h" +#include "qapi/error.h" +#include "sysemu/blockdev.h" +#include "sysemu/dma.h" +#include "hw/qdev-properties.h" +#include "hw/irq.h" +#include "migration/vmstate.h" +#include "trace.h" +#include "qom/object.h" +#include "hw/registerfields.h" + +/* This implementation is simplified: + * - Only DMA mode is implemented, with 32-bit DMA descriptor pointers. + * - FIFO is not implemented. + * - No error interrupts or conditions are generated. + * - Boot mode is not implemented. + * - Clock settings are ignored. + * + * The hardware seems to work in a manner very similar to Allwinner SD Host controller (allwinner-sdhost.c), + * notable exceptions being: + * - slightly different IDMAC descriptor structure + * - slightly different interrupt handling logic + * It is possible that Allwinner SD Host is based on an earlier version of Designware SD/MMC IP, + * or is heavily inspired by it. + */ + +#ifdef DWC_SDMMC_DEBUG +#define DEBUG(...) qemu_log(__VA_ARGS__) +#else +#define DEBUG(...) +#endif + +typedef struct { + uint32_t reserved1: 1; + uint32_t disable_int_on_completion: 1; + uint32_t last_descriptor: 1; + uint32_t first_descriptor: 1; + uint32_t second_address_chained: 1; + uint32_t end_of_ring: 1; + uint32_t reserved2: 24; + uint32_t card_error_summary: 1; + uint32_t owned_by_idmac: 1; + uint32_t buffer1_size: 13; + uint32_t buffer2_size: 13; + uint32_t reserved3: 6; + uint32_t buffer1_ptr; + union { + uint32_t buffer2_ptr; + uint32_t next_desc_ptr; + }; +} sdmmc_desc_t; + +typedef struct { + uint32_t cmd_index: 6; ///< Command index + uint32_t response_expect: 1; ///< set if response is expected + uint32_t response_long: 1; ///< 0: short response expected, 1: long response expected + uint32_t check_response_crc: 1; ///< set if controller should check response CRC + uint32_t data_expected: 1; ///< 0: no data expected, 1: data expected + uint32_t rw: 1; ///< 0: read from card, 1: write to card (don't care if no data expected) + uint32_t stream_mode: 1; ///< 0: block transfer, 1: stream transfer (don't care if no data expected) + uint32_t send_auto_stop: 1; ///< set to send stop at the end of the transfer + uint32_t wait_complete: 1; ///< 0: send command at once, 1: wait for previous command to complete + uint32_t stop_abort_cmd: 1; ///< set if this is a stop or abort command intended to stop current transfer + uint32_t send_init: 1; ///< set to send init sequence (80 clocks of 1) + uint32_t card_num: 5; ///< card number + uint32_t update_clk_reg: 1; ///< 0: normal command, 1: don't send command, just update clock registers + uint32_t read_ceata: 1; ///< set if performing read from CE-ATA device + uint32_t ccs_expected: 1; ///< set if CCS is expected from CE-ATA device + uint32_t enable_boot: 1; ///< set for mandatory boot mode + uint32_t expect_boot_ack: 1; ///< when set along with enable_boot, controller expects boot ack pattern + uint32_t disable_boot: 1; ///< set to terminate boot operation (don't set along with enable_boot) + uint32_t boot_mode: 1; ///< 0: mandatory boot operation, 1: alternate boot operation + uint32_t volt_switch: 1; ///< set to enable voltage switching (for CMD11 only) + uint32_t use_hold_reg: 1; ///< clear to bypass HOLD register + uint32_t reserved: 1; + uint32_t start_command: 1; ///< Start command; once command is sent to the card, bit is cleared. +} sdmmc_hw_cmd_t; ///< command format used in cmd register; this structure is defined to make it easier to build command values + +_Static_assert(sizeof(sdmmc_hw_cmd_t) == 4, "invalid size of sdmmc_cmd_t structure"); + + +REG32(SDMMC_CTRL, 0x00) + FIELD(SDMMC_CTRL, RST, 0, 1); + FIELD(SDMMC_CTRL, FIFO_RST, 1, 1); + FIELD(SDMMC_CTRL, DMA_RST, 2, 1); + FIELD(SDMMC_CTRL, INTEN, 4, 1); + FIELD(SDMMC_CTRL, DMAEN, 5, 1); + +REG32(SDMMC_PWREN, 0x04) +REG32(SDMMC_CLKDIV, 0x08) +REG32(SDMMC_CLKSRC, 0x0c) +REG32(SDMMC_CLKENA, 0x10) +REG32(SDMMC_TMOUT, 0x14) +REG32(SDMMC_CTYPE, 0x18) +REG32(SDMMC_BLKSIZ, 0x1c) +REG32(SDMMC_BYTCNT, 0x20) +REG32(SDMMC_INTMASK, 0x24) +REG32(SDMMC_CMDARG, 0x28) +REG32(SDMMC_CMD, 0x2c) + FIELD(SDMMC_CMD, START, 31, 1); + +REG32(SDMMC_RESP0, 0x30) +REG32(SDMMC_RESP1, 0x34) +REG32(SDMMC_RESP2, 0x38) +REG32(SDMMC_RESP3, 0x3c) + +REG32(SDMMC_MINTSTS, 0x40) +REG32(SDMMC_RINTSTS, 0x44) +REG32(SDMMC_STATUS, 0x48) +REG32(SDMMC_FIFOTH, 0x4c) +REG32(SDMMC_CDETECT, 0x50) +REG32(SDMMC_WRTPRT, 0x54) +REG32(SDMMC_GPIO, 0x58) +REG32(SDMMC_TCBCNT, 0x5c) +REG32(SDMMC_TBBCNT, 0x60) +REG32(SDMMC_DEBNCE, 0x64) +REG32(SDMMC_USRID, 0x68) +REG32(SDMMC_VERID, 0x6c) +REG32(SDMMC_HCON, 0x70) +REG32(SDMMC_UHS_REG, 0x74) +REG32(SDMMC_RST_N, 0x78) +REG32(SDMMC_BMOD, 0x80) +REG32(SDMMC_PLDMND, 0x84) +REG32(SDMMC_DBADDR, 0x88) +REG32(SDMMC_DBADDRU, 0x8c) +REG32(SDMMC_IDSTS, 0x8c) +REG32(SDMMC_IDINTEN, 0x90) +REG32(SDMMC_DSCADDR, 0x94) +REG32(SDMMC_DSCADDRL, 0x98) +REG32(SDMMC_DSCADDRU, 0x9c) +REG32(SDMMC_BUFADDRL, 0xa0) +REG32(SDMMC_BUFADDRU, 0xa4) +REG32(SDMMC_CARDTHRCTL, 0x100) +REG32(SDMMC_BACK_END_POWER, 0x104) +REG32(SDMMC_UHS_REG_EXT, 0x108) +REG32(SDMMC_EMMC_DDR_REG, 0x10c) +REG32(SDMMC_ENABLE_SHIFT, 0x110) + +#define SDMMC_INTMASK_IO_SLOT1 BIT(17) +#define SDMMC_INTMASK_IO_SLOT0 BIT(16) +#define SDMMC_INTMASK_EBE BIT(15) +#define SDMMC_INTMASK_ACD BIT(14) +#define SDMMC_INTMASK_SBE BIT(13) +#define SDMMC_INTMASK_HLE BIT(12) +#define SDMMC_INTMASK_FRUN BIT(11) +#define SDMMC_INTMASK_HTO BIT(10) +#define SDMMC_INTMASK_DTO BIT(9) +#define SDMMC_INTMASK_RTO BIT(8) +#define SDMMC_INTMASK_DCRC BIT(7) +#define SDMMC_INTMASK_RCRC BIT(6) +#define SDMMC_INTMASK_RXDR BIT(5) +#define SDMMC_INTMASK_TXDR BIT(4) +#define SDMMC_INTMASK_DATA_OVER BIT(3) +#define SDMMC_INTMASK_CMD_DONE BIT(2) +#define SDMMC_INTMASK_RESP_ERR BIT(1) +#define SDMMC_INTMASK_CD BIT(0) + +#define SDMMC_IDMAC_INTMASK_AI BIT(9) +#define SDMMC_IDMAC_INTMASK_NI BIT(8) +#define SDMMC_IDMAC_INTMASK_CES BIT(5) +#define SDMMC_IDMAC_INTMASK_DU BIT(4) +#define SDMMC_IDMAC_INTMASK_FBE BIT(2) +#define SDMMC_IDMAC_INTMASK_RI BIT(1) +#define SDMMC_IDMAC_INTMASK_TI BIT(0) + + +#define SDMMC_DMA_MAX_BUF_LEN 4096 + +static bool dwc_sdmmc_ctrl_interrupts_enabled(uint32_t ctrl_reg) +{ + return FIELD_EX32(ctrl_reg, SDMMC_CTRL, INTEN) == 1; +} + +static sdmmc_hw_cmd_t dwc_sdmmc_get_hw_cmd(DWCSDMMCState *s) +{ + sdmmc_hw_cmd_t hw_cmd; + memcpy(&hw_cmd, &s->cmd, sizeof(hw_cmd)); + return hw_cmd; +} + +static void dwc_sdmmc_handle_reset(DWCSDMMCState *s) +{ + const uint32_t reset_mask = R_SDMMC_CTRL_FIFO_RST_MASK | R_SDMMC_CTRL_RST_MASK | R_SDMMC_CTRL_DMA_RST_MASK; + if (s->ctrl & reset_mask) { + /* just clear it */ + s->ctrl &= ~reset_mask; + } +} + +static void dwc_sdmmc_update_irq(DWCSDMMCState *s) +{ + uint32_t irq = 0; + if (dwc_sdmmc_ctrl_interrupts_enabled(s->ctrl)) { + irq = s->rintsts & s->intmask; + irq |= (s->idsts & s->idinten) << 16; + } + DEBUG("%s: mask=0x%04x, sts=0x%04x irq=%d\n", __func__, s->intmask, s->rintsts, irq); + qemu_set_irq(s->irq, irq); +} + +static void dwc_sdmmc_handle_cmd(DWCSDMMCState *s) +{ + SDRequest request; + uint8_t resp[16]; + int rlen; + DEBUG("%s: hw_cmd=0x%08x\n", __func__, s->cmd); + sdmmc_hw_cmd_t hw_cmd = dwc_sdmmc_get_hw_cmd(s); + if (hw_cmd.update_clk_reg) { + goto done; + } + + request.cmd = hw_cmd.cmd_index; + request.arg = s->cmdarg; + + rlen = sdbus_do_command(&s->sdbus, &request, resp); + s->rintsts |= SDMMC_INTMASK_CMD_DONE; + if (rlen < 0) { + DEBUG("%s: error: rlen=%d\n", __func__, rlen); + } else { + if (hw_cmd.response_expect) { + if (rlen == 4 && !hw_cmd.response_long) { + s->resp[0] = ldl_be_p(&resp[0]); + s->resp[1] = s->resp[2] = s->resp[3] = 0; + + } else if (rlen == 16 && hw_cmd.response_long) { + s->resp[0] = ldl_be_p(&resp[12]); + s->resp[1] = ldl_be_p(&resp[8]); + s->resp[2] = ldl_be_p(&resp[4]); + s->resp[3] = ldl_be_p(&resp[0]); + } else { + s->rintsts |= SDMMC_INTMASK_RTO; + goto done; + } + } + } + +done: + DEBUG("%s: ending with rinsts=0x%04x\n", __func__, s->rintsts); + s->cmd = FIELD_DP32(s->cmd, SDMMC_CMD, START, 0); + dwc_sdmmc_update_irq(s); +} + +static void dwc_sdmmc_update_bytes_left(DWCSDMMCState *s, size_t bytes_done) +{ + if (s->bytes_left > bytes_done) { + s->bytes_left -= bytes_done; + } else { + s->bytes_left = 0; + } + DEBUG("%s: bytes_left = %d\n", __func__, (unsigned) s->bytes_left); + if (s->bytes_left == 0) { + DEBUG("%s: bytes_left = 0, setting SDMMC_INTMASK_DATA_OVER\n", __func__); + s->rintsts |= SDMMC_INTMASK_DATA_OVER; + } +} + +static size_t dwc_sdmmc_handle_one_desc(DWCSDMMCState *s, hwaddr desc_addr, sdmmc_desc_t *desc, bool is_write, size_t max_bytes) +{ + uint32_t num_done = 0; + uint32_t num_bytes = max_bytes; + uint8_t buf[4096]; + + /* Read descriptor */ + dma_memory_read(&address_space_memory, desc_addr, desc, sizeof(*desc), MEMTXATTRS_UNSPECIFIED); + if (desc->buffer1_size < num_bytes) { + num_bytes = desc->buffer1_size; + } + + if (desc->owned_by_idmac == 0) { + /* ran into a descriptor owned by software */ + return 0; + } + + while (num_done < num_bytes) { + /* Try to completely fill the local buffer */ + uint32_t buf_bytes = num_bytes - num_done; + if (buf_bytes > sizeof(buf)) { + buf_bytes = sizeof(buf); + } + DEBUG("%s: %sing %d bytes from descr 0x%08x\n", __func__, is_write?"write":"read", buf_bytes, (uint32_t) desc_addr); + /* Write to SD bus */ + if (is_write) { + dma_memory_read(&address_space_memory, + desc->buffer1_ptr + num_done, + buf, buf_bytes, MEMTXATTRS_UNSPECIFIED); + sdbus_write_data(&s->sdbus, buf, buf_bytes); + + /* Read from SD bus */ + } else { + sdbus_read_data(&s->sdbus, buf, buf_bytes); + dma_memory_write(&address_space_memory, + desc->buffer1_ptr + num_done, + buf, buf_bytes, MEMTXATTRS_UNSPECIFIED); + } + num_done += buf_bytes; + } + + /* Clear hold flag and flush descriptor */ + sdmmc_desc_t new_desc = *desc; + new_desc.owned_by_idmac = 0; + dma_memory_write(&address_space_memory, desc_addr, &new_desc, sizeof(new_desc), MEMTXATTRS_UNSPECIFIED); + + /* Update DMAC bits */ + s->idsts |= is_write ? SDMMC_IDMAC_INTMASK_TI : SDMMC_IDMAC_INTMASK_RI; + + return num_done; + +} + +static void dwc_sdmmc_handle_dma(DWCSDMMCState *s) +{ + sdmmc_desc_t desc; + hwaddr desc_addr = s->dscaddr; + sdmmc_hw_cmd_t hw_cmd = dwc_sdmmc_get_hw_cmd(s); + bool is_write = hw_cmd.rw == 1; + uint32_t bytes_done = 0; + + if (s->bytcnt == 0 || s->blksiz == 0 || + !FIELD_EX32(s->ctrl, SDMMC_CTRL, DMAEN)) { + DEBUG("%s: nothing to do (bytcnt=%d, blksiz=%d)\n", __func__, s->bytcnt, s->blksiz); + return; + } + + if (!is_write && !sdbus_data_ready(&s->sdbus)) { + return; + } + + while (s->bytcnt > 0) { + DEBUG("%s: handling descriptor @0x%0x, bytcnt=%d\n", __func__, (uint32_t) desc_addr, s->bytcnt); + bytes_done = dwc_sdmmc_handle_one_desc(s, desc_addr, &desc, is_write, s->bytcnt); + dwc_sdmmc_update_bytes_left(s, bytes_done); + + if (bytes_done <= s->bytcnt) { + s->bytcnt -= bytes_done; + } else { + s->bytcnt = 0; + } + + if (desc.last_descriptor || desc.owned_by_idmac == 0) { + break; + } else { + desc_addr = desc.next_desc_ptr; + s->dscaddr = desc_addr; + } + } + DEBUG("%s: finished with bytcnt=%d at dscaddr=0x%08x\n", __func__, s->bytcnt, s->dscaddr); +} + +static void dwc_sdmmc_maybe_autostop(DWCSDMMCState *s) +{ + sdmmc_hw_cmd_t hw_cmd = dwc_sdmmc_get_hw_cmd(s); + if (hw_cmd.send_auto_stop && s->bytes_left == 0) { + /* First save current command registers */ + uint32_t saved_cmd = s->cmd; + uint32_t saved_arg = s->cmdarg; + + /* Prepare stop command (CMD12) */ + sdmmc_hw_cmd_t auto_stop_cmd = hw_cmd; + auto_stop_cmd.cmd_index = 12; + memcpy(&s->cmd, &auto_stop_cmd, sizeof(s->cmd)); + s->cmdarg = 0; + + /* Put the command on SD bus */ + dwc_sdmmc_handle_cmd(s); + + /* Restore command values */ + s->cmd = saved_cmd; + s->cmdarg = saved_arg; + + /* Set IRQ status bit for automatic stop done */ + s->rintsts |= SDMMC_INTMASK_ACD; + } +} + + +static void dwc_sdmmc_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + DWCSDMMCState *s = DWC_SDMMC(opaque); + + switch (offset) { + case A_SDMMC_CTRL: + s->ctrl = value; + dwc_sdmmc_handle_reset(s); + dwc_sdmmc_update_irq(s); + break; + + case A_SDMMC_CMD: { + s->cmd = value; + if (FIELD_EX32(value, SDMMC_CMD, START)) { + dwc_sdmmc_handle_cmd(s); + dwc_sdmmc_handle_dma(s); + dwc_sdmmc_maybe_autostop(s); + dwc_sdmmc_update_irq(s); + } + break; + } + case A_SDMMC_PLDMND: + dwc_sdmmc_handle_dma(s); + dwc_sdmmc_maybe_autostop(s); + dwc_sdmmc_update_irq(s); + break; + + case A_SDMMC_CMDARG: + s->cmdarg = value; + break; + + case A_SDMMC_INTMASK: + s->intmask = value; + dwc_sdmmc_update_irq(s); + break; + + case A_SDMMC_RINTSTS: + s->rintsts &= ~value; + dwc_sdmmc_update_irq(s); + break; + + case A_SDMMC_IDSTS: + s->idsts &= ~value; + dwc_sdmmc_update_irq(s); + break; + + case A_SDMMC_IDINTEN: + s->idinten = value; + dwc_sdmmc_update_irq(s); + break; + + case A_SDMMC_DBADDR: + s->dbaddr = value; + s->dscaddr = value; + break; + + case A_SDMMC_BYTCNT: + s->bytcnt = value; + s->bytes_left = value; + break; + + case A_SDMMC_BLKSIZ: + s->blksiz = value; + break; + + default: + qemu_log_mask(LOG_UNIMP, "%s: write@0x%02x value=0x%08x\n", __func__, (uint32_t) offset, (uint32_t) value); + } + +} + +static uint64_t dwc_sdmmc_read(void *opaque, hwaddr offset, + unsigned size) +{ + DWCSDMMCState *s = DWC_SDMMC(opaque); + switch (offset) { + case A_SDMMC_CTRL: + return s->ctrl; + case A_SDMMC_INTMASK: + return s->intmask; + case A_SDMMC_CMD: + return s->cmd; + case A_SDMMC_CMDARG: + return s->cmdarg; + case A_SDMMC_RESP0 ... A_SDMMC_RESP3: + return s->resp[(offset - A_SDMMC_RESP0) / 4]; + case A_SDMMC_RINTSTS: + return s->rintsts; + case A_SDMMC_MINTSTS: + return s->intmask & s->rintsts; + case A_SDMMC_IDSTS: + return s->idsts; + case A_SDMMC_IDINTEN: + return s->idinten; + case A_SDMMC_BLKSIZ: + return s->blksiz; + case A_SDMMC_BYTCNT: + return s->bytcnt; + case A_SDMMC_DBADDR: + return s->dbaddr; + case A_SDMMC_DSCADDR: + return s->dscaddr; + default: + qemu_log_mask(LOG_UNIMP, "%s: read@0x%02x\n", __func__, (uint32_t) offset); + } + return 0; +} + + +static const MemoryRegionOps dwc_sdmmc_ops = { + .read = dwc_sdmmc_read, + .write = dwc_sdmmc_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + } +}; + + + +static Property dwc_sdmmc_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static void dwc_sdmmc_init(Object *obj) +{ + DWCSDMMCState *s = DWC_SDMMC(obj); + + qbus_init(&s->sdbus, sizeof(s->sdbus), + TYPE_SD_BUS, DEVICE(s), "sd-bus"); + + memory_region_init_io(&s->iomem, obj, &dwc_sdmmc_ops, s, + TYPE_DWC_SDMMC, 4 * KiB); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq); +} + +static void dwc_sdmmc_reset(DeviceState *dev) +{ + DWCSDMMCState *s = DWC_SDMMC(dev); + s->cmd = 0; + s->cmdarg = 0; + s->intmask = 0; + s->rintsts = 0; + s->ctrl = 0; + s->bytes_left = 0; + s->idinten = 0; + s->idsts = 0; + s->blksiz = 512; + s->bytcnt = 0; + s->dbaddr = 0; + s->pldmnd = 0; + memset(s->resp, 0, sizeof(s->resp)); +} + +static void dwc_sdmmc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = dwc_sdmmc_reset; + device_class_set_props(dc, dwc_sdmmc_properties); +} + +static TypeInfo dwc_sdmmc_info = { + .name = TYPE_DWC_SDMMC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = dwc_sdmmc_init, + .instance_size = sizeof(DWCSDMMCState), + .class_init = dwc_sdmmc_class_init, +}; + +static void dwc_sdmmc_register_types(void) +{ + type_register_static(&dwc_sdmmc_info); +} + +type_init(dwc_sdmmc_register_types) diff --git a/hw/sd/meson.build b/hw/sd/meson.build index 807ca07b7cc9..3671b16a347b 100644 --- a/hw/sd/meson.build +++ b/hw/sd/meson.build @@ -11,3 +11,4 @@ softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_sdhci.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sdhost.c')) softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_sdhci.c')) softmmu_ss.add(when: 'CONFIG_CADENCE_SDHCI', if_true: files('cadence_sdhci.c')) +softmmu_ss.add(when: 'CONFIG_DWC_SDMMC', if_true: files('dwc_sdmmc.c')) diff --git a/hw/ssi/esp32_spi.c b/hw/ssi/esp32_spi.c new file mode 100644 index 000000000000..03bef4e1a4f3 --- /dev/null +++ b/hw/ssi/esp32_spi.c @@ -0,0 +1,365 @@ +/* + * ESP32 SPI controller + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "sysemu/sysemu.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/ssi/ssi.h" +#include "hw/ssi/esp32_spi.h" +#include "hw/misc/esp32_flash_enc.h" + + + +enum { + CMD_RES = 0xab, + CMD_DP = 0xb9, + CMD_CE = 0x60, + CMD_BE = 0xD8, + CMD_SE = 0x20, + CMD_PP = 0x02, + CMD_WRSR = 0x1, + CMD_RDSR = 0x5, + CMD_RDID = 0x9f, + CMD_WRDI = 0x4, + CMD_WREN = 0x6, + CMD_READ = 0x03, +}; + + +#define ESP32_SPI_REG_SIZE 0x1000 + +static void esp32_spi_do_command(Esp32SpiState* state, uint32_t cmd_reg); + +static uint64_t esp32_spi_read(void *opaque, hwaddr addr, unsigned int size) +{ + Esp32SpiState *s = ESP32_SPI(opaque); + uint64_t r = 0; + switch (addr) { + case A_SPI_ADDR: + r = s->addr_reg; + break; + case A_SPI_CTRL: + r = s->ctrl_reg; + break; + case A_SPI_STATUS: + r = s->status_reg; + break; + case A_SPI_CTRL1: + r = s->ctrl1_reg; + break; + case A_SPI_CTRL2: + r = s->ctrl2_reg; + break; + case A_SPI_USER: + r = s->user_reg; + break; + case A_SPI_USER1: + r = s->user1_reg; + break; + case A_SPI_USER2: + r = s->user2_reg; + break; + case A_SPI_MOSI_DLEN: + r = s->mosi_dlen_reg; + break; + case A_SPI_MISO_DLEN: + r = s->miso_dlen_reg; + break; + case A_SPI_PIN: + r = s->pin_reg; + break; + case A_SPI_W0 ... A_SPI_W0 + (ESP32_SPI_BUF_WORDS - 1) * sizeof(uint32_t): + r = s->data_reg[(addr - A_SPI_W0) / sizeof(uint32_t)]; + break; + case A_SPI_EXT2: + r = 0; + break; + case A_SPI_SLAVE: + r = BIT(R_SPI_SLAVE_TRANS_DONE_SHIFT) | BIT(R_SPI_SLAVE_TRANS_INTEN_SHIFT); + break; + } + return r; +} + +static void esp32_spi_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + Esp32SpiState *s = ESP32_SPI(opaque); + switch (addr) { + case A_SPI_W0 ... A_SPI_W0 + (ESP32_SPI_BUF_WORDS - 1) * sizeof(uint32_t): + s->data_reg[(addr - A_SPI_W0) / sizeof(uint32_t)] = value; + break; + case A_SPI_ADDR: + s->addr_reg = value; + break; + case A_SPI_CTRL: + s->ctrl_reg = value; + break; + case A_SPI_STATUS: + s->status_reg = value; + break; + case A_SPI_CTRL1: + s->ctrl1_reg = value; + break; + case A_SPI_CTRL2: + s->ctrl2_reg = value; + break; + case A_SPI_USER: + s->user_reg = value; + break; + case A_SPI_USER1: + s->user1_reg = value; + break; + case A_SPI_USER2: + s->user2_reg = value; + break; + case A_SPI_MOSI_DLEN: + s->mosi_dlen_reg = value; + break; + case A_SPI_MISO_DLEN: + s->miso_dlen_reg = value; + break; + case A_SPI_PIN: + s->pin_reg = value; + break; + case A_SPI_CMD: + esp32_spi_do_command(s, value); + break; + } +} + +typedef struct Esp32SpiTransaction { + int cmd_bytes; + uint32_t cmd; + int addr_bytes; + uint32_t addr; + int data_tx_bytes; + int data_rx_bytes; + uint32_t* data; +} Esp32SpiTransaction; + +static void esp32_spi_txrx_buffer(Esp32SpiState *s, void *buf, int tx_bytes, int rx_bytes) +{ + int bytes = MAX(tx_bytes, rx_bytes); + uint8_t *c_buf = (uint8_t*) buf; + for (int i = 0; i < bytes; ++i) { + uint8_t byte = 0; + if (byte < tx_bytes) { + memcpy(&byte, c_buf + i, 1); + } + uint32_t res = ssi_transfer(s->spi, byte); + if (byte < rx_bytes) { + memcpy(c_buf + i, &res, 1); + } + } +} + +static void esp32_spi_cs_set(Esp32SpiState *s, int value) +{ + for (int i = 0; i < ESP32_SPI_CS_COUNT; ++i) { + qemu_set_irq(s->cs_gpio[i], ((s->pin_reg & (1 << i)) == 0) ? value : 1); + } +} + +static void esp32_spi_transaction(Esp32SpiState *s, Esp32SpiTransaction *t) +{ + esp32_spi_cs_set(s, 0); + esp32_spi_txrx_buffer(s, &t->cmd, t->cmd_bytes, 0); + esp32_spi_txrx_buffer(s, &t->addr, t->addr_bytes, 0); + esp32_spi_txrx_buffer(s, t->data, t->data_tx_bytes, t->data_rx_bytes); + esp32_spi_cs_set(s, 1); +} + +/* Convert one of the hardware "bitlen" registers to a byte count */ +static inline int bitlen_to_bytes(uint32_t val) +{ + return (val + 1 + 7) / 8; /* bitlen registers hold number of bits, minus one */ +} + +static void maybe_encrypt_data(Esp32SpiState *s) +{ + Esp32FlashEncryptionState* flash_enc = esp32_flash_encryption_find(); + if (esp32_flash_encryption_enabled(flash_enc)) { + esp32_flash_encryption_get_result(flash_enc, &s->data_reg[0], 8); + } +} + +static void esp32_spi_do_command(Esp32SpiState* s, uint32_t cmd_reg) +{ + Esp32SpiTransaction t = { + .cmd_bytes = 1 + }; + switch (cmd_reg) { + case R_SPI_CMD_READ_MASK: + t.cmd = CMD_READ; + t.addr_bytes = bitlen_to_bytes(FIELD_EX32(s->user1_reg, SPI_USER1, ADDR_BITLEN)); + t.addr = bswap32(s->addr_reg) >> (32 - t.addr_bytes * 8); + t.data = &s->data_reg[0]; + t.data_rx_bytes = bitlen_to_bytes(s->miso_dlen_reg); + break; + + case R_SPI_CMD_WREN_MASK: + t.cmd = CMD_WREN; + break; + + case R_SPI_CMD_WRDI_MASK: + t.cmd = CMD_WRDI; + break; + + case R_SPI_CMD_RDID_MASK: + t.cmd = CMD_RDID; + t.data = &s->data_reg[0]; + t.data_rx_bytes = 3; + break; + + case R_SPI_CMD_RDSR_MASK: + t.cmd = CMD_RDSR; + t.data = &s->status_reg; + t.data_rx_bytes = 1; + break; + + case R_SPI_CMD_WRSR_MASK: + t.cmd = CMD_WRSR; + t.data = &s->status_reg; + t.data_tx_bytes = 1; + break; + + case R_SPI_CMD_PP_MASK: + maybe_encrypt_data(s); + t.cmd = CMD_PP; + t.data = &s->data_reg[0]; + t.addr_bytes = bitlen_to_bytes(FIELD_EX32(s->user1_reg, SPI_USER1, ADDR_BITLEN)); + t.addr = bswap32(s->addr_reg) >> 8; + t.data = &s->data_reg[0]; + t.data_tx_bytes = s->addr_reg >> 24; + break; + + case R_SPI_CMD_SE_MASK: + t.cmd = CMD_SE; + t.addr_bytes = bitlen_to_bytes(FIELD_EX32(s->user1_reg, SPI_USER1, ADDR_BITLEN)); + t.addr = bswap32(s->addr_reg) >> (32 - t.addr_bytes * 8); + break; + + case R_SPI_CMD_BE_MASK: + t.cmd = CMD_BE; + t.addr_bytes = bitlen_to_bytes(FIELD_EX32(s->user1_reg, SPI_USER1, ADDR_BITLEN)); + t.addr = bswap32(s->addr_reg) >> (32 - t.addr_bytes * 8); + break; + + case R_SPI_CMD_CE_MASK: + t.cmd = CMD_CE; + break; + + case R_SPI_CMD_DP_MASK: + t.cmd = CMD_DP; + break; + + case R_SPI_CMD_RES_MASK: + t.cmd = CMD_RES; + t.data = &s->data_reg[0]; + t.data_rx_bytes = 3; + break; + + case R_SPI_CMD_USR_MASK: + maybe_encrypt_data(s); + if (FIELD_EX32(s->user_reg, SPI_USER, COMMAND) || FIELD_EX32(s->user2_reg, SPI_USER2, COMMAND_BITLEN)) { + t.cmd = FIELD_EX32(s->user2_reg, SPI_USER2, COMMAND_VALUE); + t.cmd_bytes = bitlen_to_bytes(FIELD_EX32(s->user2_reg, SPI_USER2, COMMAND_BITLEN)); + } else { + t.cmd_bytes = 0; + } + if (FIELD_EX32(s->user_reg, SPI_USER, ADDR)) { + t.addr_bytes = bitlen_to_bytes(FIELD_EX32(s->user1_reg, SPI_USER1, ADDR_BITLEN)); + t.addr = bswap32(s->addr_reg); + } + if (FIELD_EX32(s->user_reg, SPI_USER, MOSI)) { + t.data = &s->data_reg[0]; + t.data_tx_bytes = bitlen_to_bytes(s->mosi_dlen_reg); + } + if (FIELD_EX32(s->user_reg, SPI_USER, MISO)) { + t.data = &s->data_reg[0]; + t.data_rx_bytes = bitlen_to_bytes(s->miso_dlen_reg); + } + break; + default: + return; + } + esp32_spi_transaction(s, &t); +} + + +static const MemoryRegionOps esp32_spi_ops = { + .read = esp32_spi_read, + .write = esp32_spi_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_spi_reset(DeviceState *dev) +{ + Esp32SpiState *s = ESP32_SPI(dev); + s->pin_reg = 0x6; + s->user1_reg = FIELD_DP32(0, SPI_USER1, ADDR_BITLEN, 23); + s->user1_reg = FIELD_DP32(s->user1_reg, SPI_USER1, DUMMY_CYCLELEN, 7); + s->user2_reg = FIELD_DP32(0, SPI_USER2, COMMAND_BITLEN, 4); + s->user2_reg = FIELD_DP32(s->user2_reg, SPI_USER2, COMMAND_VALUE, 0); + s->status_reg = 0; +} + +static void esp32_spi_realize(DeviceState *dev, Error **errp) +{ +} + +static void esp32_spi_init(Object *obj) +{ + Esp32SpiState *s = ESP32_SPI(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_spi_ops, s, + TYPE_ESP32_SPI, ESP32_SPI_REG_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + + s->spi = ssi_create_bus(DEVICE(s), "spi"); + qdev_init_gpio_out_named(DEVICE(s), &s->cs_gpio[0], SSI_GPIO_CS, ESP32_SPI_CS_COUNT); +} + +static Property esp32_spi_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32_spi_reset; + dc->realize = esp32_spi_realize; + device_class_set_props(dc, esp32_spi_properties); +} + +static const TypeInfo esp32_spi_info = { + .name = TYPE_ESP32_SPI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32SpiState), + .instance_init = esp32_spi_init, + .class_init = esp32_spi_class_init +}; + +static void esp32_spi_register_types(void) +{ + type_register_static(&esp32_spi_info); +} + +type_init(esp32_spi_register_types) diff --git a/hw/ssi/esp32c3_spi.c b/hw/ssi/esp32c3_spi.c new file mode 100644 index 000000000000..365a6e991c39 --- /dev/null +++ b/hw/ssi/esp32c3_spi.c @@ -0,0 +1,455 @@ +/* + * ESP32 SPI controller + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "sysemu/sysemu.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/ssi/ssi.h" +#include "hw/ssi/esp32c3_spi.h" +#include "qemu/error-report.h" + +#define SPI1_DEBUG 0 +#define SPI1_WARNING 0 + + +enum { + CMD_RES = 0xab, + CMD_DP = 0xb9, + CMD_CE = 0x60, + CMD_BE = 0xd8, + CMD_SE = 0x20, + CMD_PP = 0x02, + CMD_WRSR = 0x1, + CMD_RDSR = 0x5, + CMD_RDID = 0x9f, + CMD_WRDI = 0x4, + CMD_WREN = 0x6, + CMD_READ = 0x03, + CMD_HPM = 0xa3, +}; + + +typedef struct ESP32C3SpiTransaction { + uint32_t cmd; + uint32_t cmd_bytes; + + uint32_t addr; + uint32_t addr_bytes; + + uint32_t dummy_bytes; + + void* data; + uint32_t tx_bytes; + uint32_t rx_bytes; +} ESP32C3SpiTransaction; + + +static uint64_t esp32c3_spi_read(void *opaque, hwaddr addr, unsigned int size) +{ + ESP32C3SpiState *s = ESP32C3_SPI(opaque); + + uint64_t r = 0; + switch (addr) { + case A_SPI_MEM_CMD: + r = 0; + break; + case A_SPI_MEM_ADDR: + r = s->mem_addr; + break; + case A_SPI_MEM_CTRL: + r = s->mem_ctrl; + break; + case A_SPI_MEM_CTRL1: + r = s->mem_ctrl1; + break; + case A_SPI_MEM_CTRL2: + r = s->mem_ctrl2; + break; + case A_SPI_MEM_CLOCK: + r = s->mem_clock; + break; + case A_SPI_MEM_USER: + r = s->mem_user; + break; + case A_SPI_MEM_USER1: + r = s->mem_user1; + break; + case A_SPI_MEM_USER2: + r = s->mem_user2; + break; + case A_SPI_MEM_MISO_DLEN: + r = s->mem_miso_len; + break; + case A_SPI_MEM_MOSI_DLEN: + r = s->mem_mosi_len; + break; + case A_SPI_MEM_RD_STATUS: + r = s->mem_rd_st; + break; + case A_SPI_MEM_W0...A_SPI_MEM_W15: + r = s->data_reg[(addr - A_SPI_MEM_W0) / sizeof(uint32_t)]; + break; + case A_SPI_MEM_SUS_STATUS: + r = s->mem_sus_st; + break; + default: +#if SPI1_WARNING + warn_report("[SPI1] Unsupported read to 0x%lx", addr); +#endif + break; + } + +#if SPI1_DEBUG + info_report("[SPI1] Reading 0x%lx (0x%lx)", addr, r); +#endif + + return r; +} + + +static void esp32c3_spi_txrx_buffer(ESP32C3SpiState *s, + const void *tx, int tx_bytes, + void *rx, int rx_bytes) +{ + int bytes = MAX(tx_bytes, rx_bytes); + for (int i = 0; i < bytes; ++i) { + uint8_t byte = 0; + if (byte < tx_bytes) { + memcpy(&byte, tx + i, 1); + } + uint32_t res = ssi_transfer(s->spi, byte); + if (byte < rx_bytes) { + memcpy(rx + i, &res, 1); + } + } +} + +static void esp32c3_spi_dummy_cycles(ESP32C3SpiState *s, uint32_t dummy_bytes) { + for (int i = 0; i < dummy_bytes; i++) { + ssi_transfer(s->spi, 0); + } +} + +static void esp32c3_spi_perform_transaction(ESP32C3SpiState *s, const ESP32C3SpiTransaction *t) +{ + qemu_set_irq(s->cs_gpio[0], 0); + esp32c3_spi_txrx_buffer(s, &t->cmd, t->cmd_bytes, NULL, 0); + esp32c3_spi_txrx_buffer(s, &t->addr, t->addr_bytes, NULL, 0); + esp32c3_spi_dummy_cycles(s, t->dummy_bytes); + esp32c3_spi_txrx_buffer(s, t->data, t->tx_bytes, t->data, t->rx_bytes); + qemu_set_irq(s->cs_gpio[0], 1); +} + + +static inline void esp32c3_spi_get_addr(ESP32C3SpiState *s, uint32_t* addr, uint32_t* len) +{ + const uint32_t address = FIELD_EX32(s->mem_addr, SPI_MEM_ADDR, USR_ADDR_VALUE); + /* SPI Flash expects the address to be sent with MSB first. We make the assumption that + * the host computer uses a little-endian CPU. */ + *addr = bswap32(address); + + const uint32_t address_len = FIELD_EX32(s->mem_user1, SPI_MEM_USER1, USR_ADDR_BITLEN); + *len = (address_len + 1) / 8; +} + +static inline void esp32c3_spi_get_dummy(ESP32C3SpiState *s, uint32_t* len) +{ + const uint32_t dummy_count = FIELD_EX32(s->mem_user1, SPI_MEM_USER1, USR_DUMMY_CYCLELEN); + + /* Dummy cycles are interpreted as bytes by the emulated SPI Flash. As such, we shall convert + * our dummy cycles count in bytes, rounding it up. For example: + * 0 cycles = 0 byte + * 1 cycle = 1 byte + * ... + * 8 cycles = 1 byte + * 9 cycles = 2 bytes + * etc.. + */ + *len = (dummy_count + 7) / 8; +} + +static void esp32c3_spi_begin_transaction(ESP32C3SpiState *s) +{ + ESP32C3SpiTransaction t = { + .data = s->data_reg + }; + + /* Get the number of bytes to read from the device */ + if (s->mem_user & R_SPI_MEM_USER_USR_MISO_MASK) { + t.rx_bytes = FIELD_EX32(s->mem_miso_len, SPI_MEM_MISO_DLEN, USR_MISO_DBITLEN); + t.rx_bytes = (t.rx_bytes + 1) / 8; + } + + /* and the number of bytes to write to the device */ + if (s->mem_user & R_SPI_MEM_USER_USR_MOSI_MASK) { + t.tx_bytes = FIELD_EX32(s->mem_mosi_len, SPI_MEM_MOSI_DLEN, USR_MOSI_DBITLEN); + t.tx_bytes = (t.tx_bytes + 1) / 8; + } + + /* Get the command and its length, in bytes + * In theory we should test mem_user's command bit. In practice, if we do, `esptool` + * cannot write flash successfully and detects an error */ + t.cmd = FIELD_EX32(s->mem_user2, SPI_MEM_USER2, USR_COMMAND_VALUE); + t.cmd_bytes = FIELD_EX32(s->mem_user2, SPI_MEM_USER2, USR_COMMAND_BITLEN); + t.cmd_bytes = (t.cmd_bytes + 1) / 8; + + /* Get the address and its length, in bytes */ + if (s->mem_user & R_SPI_MEM_USER_USR_ADDR_MASK) { + esp32c3_spi_get_addr(s, &t.addr, &t.addr_bytes); + if (t.addr_bytes > 0 && t.addr_bytes <= 4) { + t.addr = t.addr >> (32 - t.addr_bytes * 8); + } + + /* Only calculate and include dummy cycles when the USR_DUMMY bit is set! */ + if (s->mem_user & R_SPI_MEM_USER_USR_DUMMY_MASK) { + esp32c3_spi_get_dummy(s, &t.dummy_bytes); + } + } + + esp32c3_spi_perform_transaction(s, &t); +} + + +static void esp32c3_spi_special_command(ESP32C3SpiState *s, uint32_t command) +{ + ESP32C3SpiTransaction t= { + .cmd_bytes = 1 + }; + + switch (command >> 19 << 19) { + case R_SPI_MEM_CMD_FLASH_READ_MASK: + t.cmd = CMD_READ; + esp32c3_spi_get_addr(s, &t.addr, &t.addr_bytes); + t.addr = t.addr >> (32 - t.addr_bytes * 8); + t.data = s->data_reg; + t.rx_bytes = (FIELD_EX32(s->mem_miso_len, SPI_MEM_MISO_DLEN, USR_MISO_DBITLEN) + 1) / 8; + break; + + case R_SPI_MEM_CMD_FLASH_WREN_MASK: + t.cmd = CMD_WREN; + break; + + case R_SPI_MEM_CMD_FLASH_WRDI_MASK: + t.cmd = CMD_WRDI; + break; + + case R_SPI_MEM_CMD_FLASH_RDID_MASK: + t.cmd = CMD_RDID; + t.data = s->data_reg; + t.rx_bytes = 3; + break; + + case R_SPI_MEM_CMD_FLASH_RDSR_MASK: + t.cmd = CMD_RDSR; + t.data = &s->mem_rd_st; + t.rx_bytes = 1; + break; + + case R_SPI_MEM_CMD_FLASH_WRSR_MASK: + t.cmd = CMD_WRSR; + t.data = &s->mem_rd_st; + t.tx_bytes = 1; + break; + + case R_SPI_MEM_CMD_FLASH_PP_MASK: + t.cmd = CMD_PP; + t.data = s->data_reg; + esp32c3_spi_get_addr(s, &t.addr, &t.addr_bytes); + /* The number of bytes to process is in the upper-byte of address */ + t.tx_bytes = (s->mem_addr >> 24) & 0xff; + /** + * Page program expects a 24-bit page address, if the one written in mem_addr was + * 0xNN_33_00_02 (where is "do not care"), after calling `esp32c3_spi_get_addr`, the + * address becomes 0x02_00_33_NN. Thus, if we cast it to a byte array, arr[0] would give + * `NN`, instead of `33`. We need to adjust the value in address. + */ + t.addr = t.addr >> 8; + break; + + case R_SPI_MEM_CMD_FLASH_SE_MASK: + t.cmd = CMD_SE; + esp32c3_spi_get_addr(s, &t.addr, &t.addr_bytes); + /* For the same reasons as explained above, we need to adjust `t.addr`, but here, the shift + * to perform is not fixed and depends on the address length */ + t.addr = t.addr >> (32 - t.addr_bytes * 8); + break; + + case R_SPI_MEM_CMD_FLASH_BE_MASK: + t.cmd = CMD_BE; + esp32c3_spi_get_addr(s, &t.addr, &t.addr_bytes); + t.addr = t.addr >> (32 - t.addr_bytes * 8); + break; + + case R_SPI_MEM_CMD_FLASH_CE_MASK: + t.cmd = CMD_CE; + break; + + case R_SPI_MEM_CMD_FLASH_DP_MASK: + t.cmd = CMD_DP; + break; + + case R_SPI_MEM_CMD_FLASH_RES_MASK: + t.cmd = CMD_RES; + t.data = s->data_reg; + t.rx_bytes = 3; + break; + + case R_SPI_MEM_CMD_FLASH_HPM_MASK: + t.cmd = CMD_HPM; + /* HPM needs 24 dummy cycles, so sent 3 random bytes */ + t.data = s->data_reg; + t.rx_bytes = 3; + break; + + default: +#if SPI1_WARNING + warn_report("[SPI1] Unsupported special command %x", command); +#endif + return; + } + esp32c3_spi_perform_transaction(s, &t); +} + + +static void esp32c3_spi_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + ESP32C3SpiState *s = ESP32C3_SPI(opaque); + uint32_t wvalue = (uint32_t) value; + +#if SPI1_DEBUG + info_report("[SPI1] Writing 0x%lx = %08lx", addr, value); +#endif + + switch (addr) { + case A_SPI_MEM_CMD: + if(wvalue & R_SPI_MEM_CMD_USR_MASK) { + esp32c3_spi_begin_transaction(s); + } else { + esp32c3_spi_special_command(s, wvalue); + } + break; + case A_SPI_MEM_ADDR: + s->mem_addr = wvalue; + break; + case A_SPI_MEM_CTRL: + s->mem_ctrl = wvalue; + break; + case A_SPI_MEM_CTRL1: + s->mem_ctrl1 = wvalue; + break; + case A_SPI_MEM_CTRL2: + s->mem_ctrl2 = wvalue; + break; + case A_SPI_MEM_CLOCK: + s->mem_clock = wvalue; + break; + case A_SPI_MEM_USER: + s->mem_user = wvalue; + break; + case A_SPI_MEM_USER1: + s->mem_user1 = wvalue; + break; + case A_SPI_MEM_USER2: + s->mem_user2 = wvalue; + break; + case A_SPI_MEM_MISO_DLEN: + s->mem_miso_len = wvalue; + break; + case A_SPI_MEM_MOSI_DLEN: + s->mem_mosi_len = wvalue; + break; + case A_SPI_MEM_RD_STATUS: + s->mem_rd_st = wvalue; + break; + case A_SPI_MEM_W0...A_SPI_MEM_W15: + s->data_reg[(addr - A_SPI_MEM_W0) / sizeof(uint32_t)] = wvalue; + break; + case A_SPI_MEM_SUS_STATUS: + s->mem_sus_st = wvalue; + break; + default: +#if SPI1_WARNING + warn_report("[SPI1] Unsupported write to 0x%lx (%08lx)", addr, value); +#endif + break; + } + +} + +/* Convert one of the hardware "bitlen" registers to a byte count */ +static inline int bitlen_to_bytes(uint32_t val) +{ + return (val + 1 + 7) / 8; /* bitlen registers hold number of bits, minus one */ +} + +static const MemoryRegionOps esp32c3_spi_ops = { + .read = esp32c3_spi_read, + .write = esp32c3_spi_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32c3_spi_reset(DeviceState *dev) +{ + ESP32C3SpiState *s = ESP32C3_SPI(dev); + memset(s->data_reg, 0, ESP32C3_SPI_BUF_WORDS * sizeof(uint32_t)); +} + +static void esp32c3_spi_realize(DeviceState *dev, Error **errp) +{ +} + +static void esp32c3_spi_init(Object *obj) +{ + ESP32C3SpiState *s = ESP32C3_SPI(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32c3_spi_ops, s, + TYPE_ESP32C3_SPI, ESP32C3_SPI_IO_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + // sysbus_init_irq(sbd, &s->irq); + + s->spi = ssi_create_bus(DEVICE(s), "spi"); + qdev_init_gpio_out_named(DEVICE(s), &s->cs_gpio[0], SSI_GPIO_CS, ESP32C3_SPI_CS_COUNT); +} + +static Property esp32c3_spi_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32c3_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32c3_spi_reset; + dc->realize = esp32c3_spi_realize; + device_class_set_props(dc, esp32c3_spi_properties); +} + +static const TypeInfo esp32c3_spi_info = { + .name = TYPE_ESP32C3_SPI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32C3SpiState), + .instance_init = esp32c3_spi_init, + .class_init = esp32c3_spi_class_init +}; + +static void esp32c3_spi_register_types(void) +{ + type_register_static(&esp32c3_spi_info); +} + +type_init(esp32c3_spi_register_types) diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build index 904a47161a45..1428694ec1ae 100644 --- a/hw/ssi/meson.build +++ b/hw/ssi/meson.build @@ -10,4 +10,6 @@ softmmu_ss.add(when: 'CONFIG_XILINX_SPIPS', if_true: files('xilinx_spips.c')) softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-ospi.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_spi.c')) softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_spi.c')) +softmmu_ss.add(when: 'CONFIG_XTENSA_ESP32', if_true: files('esp32_spi.c')) +softmmu_ss.add(when: 'CONFIG_RISCV_ESP32C3', if_true: files('esp32c3_spi.c')) softmmu_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_spi_host.c')) diff --git a/hw/timer/esp32_frc_timer.c b/hw/timer/esp32_frc_timer.c new file mode 100644 index 000000000000..7bfc4a198621 --- /dev/null +++ b/hw/timer/esp32_frc_timer.c @@ -0,0 +1,245 @@ +/* + * ESP32 FRC (legacy) timer + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "qapi/visitor.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/boards.h" +#include "hw/timer/esp32_frc_timer.h" +#include "trace.h" + +static uint64_t esp32_frc_timer_get_count(Esp32FrcTimerState *s, uint64_t ns_now) +{ + if (!s->enable) { + return s->count_base; + } + uint64_t ns_from_base = ns_now - s->ns_base; + uint64_t ticks_from_base = muldiv64(ns_from_base, s->apb_freq, NANOSECONDS_PER_SECOND * s->prescaler); + uint64_t count = (ticks_from_base + s->count_base) & s->count_mask; + return count; +} + +static uint64_t esp32_frc_timer_count_to_ns(Esp32FrcTimerState *s, uint64_t count) +{ + return muldiv64(count, NANOSECONDS_PER_SECOND * s->prescaler, s->apb_freq); +} + +static void esp32_frc_timer_update_alarm(Esp32FrcTimerState *s, uint64_t ticks_alarm, uint32_t ticks_now, uint64_t ns_now) +{ + if (ticks_alarm <= ticks_now) { + ticks_alarm += (1ULL << 32); + } + uint64_t ticks_to_alarm = ticks_alarm - ticks_now; + uint64_t ns_to_alarm = esp32_frc_timer_count_to_ns(s, ticks_to_alarm); + trace_esp32_frc_timer_update_alarm(ns_now, ticks_now, ticks_alarm, ns_to_alarm); + timer_mod_anticipate_ns(&s->alarm_timer, ns_now + ns_to_alarm); +} + +static void esp32_frc_timer_cb(void *opaque) +{ + Esp32FrcTimerState *s = ESP32_FRC_TIMER(opaque); + uint64_t ns_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + uint32_t count_now = esp32_frc_timer_get_count(s, ns_now); + trace_esp32_frc_timer_cb(ns_now, count_now); + + if (s->level_int) { + s->level_int_status = true; + qemu_irq_raise(s->irq); + } else { + qemu_irq_pulse(s->irq); + } + + if (s->autoload) { + esp32_frc_timer_update_alarm(s, s->alarm_reg, count_now, ns_now); + } +} + +static void esp32_frc_timer_update_config(Esp32FrcTimerState *s, + bool enable, bool level_int, bool autoload, int prescaler) +{ + uint64_t ns_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + uint32_t count_now = esp32_frc_timer_get_count(s, ns_now); + trace_esp32_frc_timer_update_config(ns_now, count_now, enable, level_int, autoload, prescaler); + + s->count_base = count_now; + s->ns_base = ns_now; + + if (!enable) { + timer_del(&s->alarm_timer); + } else { + esp32_frc_timer_update_alarm(s, s->alarm_reg, count_now, ns_now); + } + + s->enable = enable; + s->level_int = level_int; + s->autoload = autoload; + s->prescaler = prescaler; +} + + +static uint64_t esp32_frc_timer_read(void *opaque, hwaddr addr, unsigned int size) +{ + Esp32FrcTimerState *s = ESP32_FRC_TIMER(opaque); + uint64_t r = 0; + switch (addr) { + case A_FRC_TIMER_ALARM: + r = s->alarm_reg; + break; + case A_FRC_TIMER_LOAD: + r = s->load_reg; + break; + case A_FRC_TIMER_CTRL: + r = FIELD_DP32(r, FRC_TIMER_CTRL, LEVEL_INT, s->level_int); + r = FIELD_DP32(r, FRC_TIMER_CTRL, PRESCALER, (s->prescaler == 1) ? 0 : (s->prescaler == 16) ? 2 : 4); + r = FIELD_DP32(r, FRC_TIMER_CTRL, AUTOLOAD, s->autoload); + r = FIELD_DP32(r, FRC_TIMER_CTRL, ENABLE, s->enable); + r = FIELD_DP32(r, FRC_TIMER_CTRL, STATUS, s->level_int_status); + break; + case A_FRC_TIMER_COUNT: { + uint64_t ns_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + r = (uint32_t) esp32_frc_timer_get_count(s, ns_now); + break; + } + case A_FRC_TIMER_INT_CLR: + default: + break; + } + trace_esp32_frc_timer_read(addr, r); + return r; +} + +static void esp32_frc_timer_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + Esp32FrcTimerState *s = ESP32_FRC_TIMER(opaque); + trace_esp32_frc_timer_write(addr, value); + switch (addr) { + case A_FRC_TIMER_INT_CLR: + if (value & 1) { + if (s->level_int_status) { + qemu_irq_lower(s->irq); + } + s->level_int_status = false; + } + break; + case A_FRC_TIMER_LOAD: + s->load_reg = value; + s->ns_base = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + s->count_base = value; + break; + case A_FRC_TIMER_CTRL: { + bool level_int = FIELD_EX32(value, FRC_TIMER_CTRL, LEVEL_INT); + int prescaler = FIELD_EX32(value, FRC_TIMER_CTRL, PRESCALER); + bool autoload = FIELD_EX32(value, FRC_TIMER_CTRL, AUTOLOAD); + bool enable = FIELD_EX32(value, FRC_TIMER_CTRL, ENABLE); + if (prescaler == 2) { + prescaler = 16; + } else if (prescaler == 4) { + prescaler = 256; + } else { + prescaler = 1; + } + esp32_frc_timer_update_config(s, enable, level_int, autoload, prescaler); + break; + } + case A_FRC_TIMER_ALARM: { + uint64_t ns_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + uint32_t count_now = esp32_frc_timer_get_count(s, ns_now); + s->alarm_reg = value; + esp32_frc_timer_update_alarm(s, s->alarm_reg, count_now, ns_now); + break; + } + } +} + +static void esp32_frc_timer_set_apb_freq(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + Esp32FrcTimerState *s = ESP32_FRC_TIMER(opaque); + visit_type_uint32(v, name, &s->apb_freq, errp); + +} + +static const MemoryRegionOps esp32_frc_timer_ops = { + .read = esp32_frc_timer_read, + .write = esp32_frc_timer_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_frc_timer_reset(DeviceState *dev) +{ + Esp32FrcTimerState *s = ESP32_FRC_TIMER(dev); + + s->prescaler = 1; +} + +static void esp32_frc_timer_realize(DeviceState *dev, Error **errp) +{ +} + +static void esp32_frc_timer_init(Object *obj) +{ + Esp32FrcTimerState *s = ESP32_FRC_TIMER(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_frc_timer_ops, s, + TYPE_ESP32_FRC_TIMER, A_FRC_TIMER_ALARM + 4); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + + object_property_add(obj, "apb_freq", "uint32", + NULL, + esp32_frc_timer_set_apb_freq, + NULL, + obj); + + + timer_init_ns(&s->alarm_timer, QEMU_CLOCK_VIRTUAL, esp32_frc_timer_cb, s); + + s->apb_freq = 80000000; + s->count_mask = UINT32_MAX; + s->has_alarm = true; +} + +static Property esp32_frc_timer_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32_frc_timer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32_frc_timer_reset; + dc->realize = esp32_frc_timer_realize; + device_class_set_props(dc, esp32_frc_timer_properties); +} + +static const TypeInfo esp32_frc_timer_info = { + .name = TYPE_ESP32_FRC_TIMER, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32FrcTimerState), + .instance_init = esp32_frc_timer_init, + .class_init = esp32_frc_timer_class_init +}; + +static void esp32_frc_timer_register_types(void) +{ + type_register_static(&esp32_frc_timer_info); +} + +type_init(esp32_frc_timer_register_types) diff --git a/hw/timer/esp32_timg.c b/hw/timer/esp32_timg.c new file mode 100644 index 000000000000..8f29c62bbe94 --- /dev/null +++ b/hw/timer/esp32_timg.c @@ -0,0 +1,664 @@ +/* + * ESP32 "Timer Group" peripheral + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "qapi/visitor.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/registerfields.h" +#include "hw/boards.h" +#include "hw/timer/esp32_timg.h" + + +#define TIMG_REGFILE_SIZE 0x100 + +static uint64_t esp32_timg_timer_get_count(Esp32TimgTimerState *s, uint64_t ns_now); +static uint64_t esp32_timg_timer_count_to_ns(Esp32TimgTimerState *s, uint64_t count); +static void esp32_timg_timer_update_config(Esp32TimgTimerState *ts); +static void esp32_timg_timer_update_alarm(Esp32TimgTimerState *ts, uint64_t ns_now); +static void esp32_timg_timer_reload(Esp32TimgTimerState *ts, uint64_t ns_now); +static void esp32_timg_do_calibration(Esp32TimgState* s); +static void esp32_timg_int_update(Esp32TimgState *s); +static bool esp32_timg_wdt_protected(Esp32TimgWdtState *ws); +static void esp32_timg_wdt_update_config(Esp32TimgWdtState *ws); +static void esp32_timg_wdt_feed(Esp32TimgWdtState *ws); +static void esp32_timg_wdt_arm(Esp32TimgWdtState *ws, uint64_t ns_now); + + +#define TIMG_DEBUG_LOG(...) // qemu_log(__VA_ARGS__) + +static inline void set_low_word(uint64_t *dst, uint32_t word) +{ + *dst = (*dst & ~UINT32_MAX) | word; +} + +static inline void set_high_word(uint64_t *dst, uint32_t word) +{ + *dst = (*dst & UINT32_MAX) | (((uint64_t)word) << 32); +} + +static inline qemu_irq get_level_irq(Esp32TimgState* s, Esp32TimgInterruptType it) +{ + return s->irqs[it]; +} + +static inline qemu_irq get_edge_irq(Esp32TimgState* s, Esp32TimgInterruptType it) +{ + return s->irqs[TIMG_INT_MAX + it]; +} + + +static uint64_t esp32_timg_read(void *opaque, hwaddr addr, unsigned int size) +{ + Esp32TimgState *s = ESP32_TIMG(opaque); + Esp32TimgTimerState *ts = NULL; + if (addr <= A_TIMG_T0LOAD) { + ts = &s->t0; + } else if (addr <= A_TIMG_T1LOAD) { + ts = &s->t1; + } else if (addr >= A_TIMG_LACTCONFIG && addr < A_TIMG_LACTLOAD) { + ts = &s->lact; + } + uint64_t r = 0; + switch (addr) { + case A_TIMG_T0CONFIG: + case A_TIMG_T1CONFIG: + case A_TIMG_LACTCONFIG: + r = ts->config_reg; + break; + case A_TIMG_T0LO: + case A_TIMG_T1LO: + case A_TIMG_LACTLO: + r = ts->last_val & UINT32_MAX; + break; + case A_TIMG_T0HI: + case A_TIMG_T1HI: + case A_TIMG_LACTHI: + r = ts->last_val >> 32; + break; + case A_TIMG_T0LOADLO: + case A_TIMG_T1LOADLO: + case A_TIMG_LACTLOADLO: + r = ts->load_val & UINT32_MAX; + break; + case A_TIMG_T0LOADHI: + case A_TIMG_T1LOADHI: + case A_TIMG_LACTLOADHI: + r = ts->load_val >> 32; + break; + case A_TIMG_T0ALARMLO: + case A_TIMG_T1ALARMLO: + case A_TIMG_LACTALARMLO: + r = ts->alarm_val & UINT32_MAX; + break; + case A_TIMG_T0ALARMHI: + case A_TIMG_T1ALARMHI: + case A_TIMG_LACTALARMHI: + r = ts->alarm_val >> 32; + break; + + case A_TIMG_WDTCONFIG0: + r = s->wdt.config0_reg; + break; + case A_TIMG_WDTCONFIG1: + r = FIELD_DP32(r, TIMG_WDTCONFIG1, PRESCALE, s->wdt.prescale); + break; + case A_TIMG_WDTCONFIG2: + case A_TIMG_WDTCONFIG3: + case A_TIMG_WDTCONFIG4: + case A_TIMG_WDTCONFIG5: { + int stage = (addr - A_TIMG_WDTCONFIG2) / 4; + r = s->wdt.timeout[stage]; + break; + } + case A_TIMG_WDTPROTECT: + r = s->wdt.protect_reg; + break; + + case A_TIMG_RTCCALICFG: + r = FIELD_DP32(r, TIMG_RTCCALICFG, START, s->rtc_cal_start); + r = FIELD_DP32(r, TIMG_RTCCALICFG, MAX, s->rtc_cal_max); + r = FIELD_DP32(r, TIMG_RTCCALICFG, RDY, s->rtc_cal_ready); + r = FIELD_DP32(r, TIMG_RTCCALICFG, CLK_SEL, s->rtc_cal_clk_sel); + break; + case A_TIMG_RTCCALICFG1: + r = FIELD_DP32(0, TIMG_RTCCALICFG1, VALUE, s->rtc_cal_value); + break; + + case A_TIMG_INT_ENA: + r = s->int_ena; + break; + case A_TIMG_INT_RAW: + r = s->int_raw; + break; + case A_TIMG_INT_ST: + r = s->int_ena & s->int_raw; + break; + } + return r; +} + +static void esp32_timg_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + Esp32TimgState *s = ESP32_TIMG(opaque); + Esp32TimgTimerState *ts = NULL; + if (addr <= A_TIMG_T0LOAD) { + ts = &s->t0; + } else if (addr <= A_TIMG_T1LOAD) { + ts = &s->t1; + } else if (addr >= A_TIMG_LACTCONFIG && addr <= A_TIMG_LACTLOAD) { + ts = &s->lact; + } + + switch (addr) { + case A_TIMG_T0CONFIG: + case A_TIMG_T1CONFIG: + case A_TIMG_LACTCONFIG: + ts->config_reg = value; + esp32_timg_timer_update_config(ts); + break; + case A_TIMG_T0UPDATE: + case A_TIMG_T1UPDATE: + case A_TIMG_LACTUPDATE: { + uint64_t ns_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + ts->last_val = esp32_timg_timer_get_count(ts, ns_now); + break; + } + case A_TIMG_T0LOADLO: + case A_TIMG_T1LOADLO: + case A_TIMG_LACTLOADLO: + set_low_word(&ts->load_val, value); + break; + case A_TIMG_T0LOADHI: + case A_TIMG_T1LOADHI: + case A_TIMG_LACTLOADHI: + set_high_word(&ts->load_val, value); + break; + case A_TIMG_T0LOAD: + case A_TIMG_T1LOAD: + case A_TIMG_LACTLOAD: { + uint64_t ns_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + esp32_timg_timer_reload(ts, ns_now); + break; + } + case A_TIMG_T0ALARMLO: + case A_TIMG_T1ALARMLO: + case A_TIMG_LACTALARMLO: + set_low_word(&ts->alarm_val, value); + break; + case A_TIMG_T0ALARMHI: + case A_TIMG_T1ALARMHI: + case A_TIMG_LACTALARMHI: + set_high_word(&ts->alarm_val, value); + break; + + case A_TIMG_WDTCONFIG0: + if (!esp32_timg_wdt_protected(&s->wdt)) { + s->wdt.config0_reg = value; + esp32_timg_wdt_update_config(&s->wdt); + } else { + TIMG_DEBUG_LOG("failed to write TIMG_WDTCONFIG0, write protected (0x%08x)\n", s->wdt.protect_reg); + } + break; + case A_TIMG_WDTCONFIG1: + if (!esp32_timg_wdt_protected(&s->wdt)) { + s->wdt.config1_reg = value; + esp32_timg_wdt_update_config(&s->wdt); + } + break; + case A_TIMG_WDTCONFIG2: + case A_TIMG_WDTCONFIG3: + case A_TIMG_WDTCONFIG4: + case A_TIMG_WDTCONFIG5: { + if (!esp32_timg_wdt_protected(&s->wdt)) { + int stage = (addr - A_TIMG_WDTCONFIG2) / 4; + s->wdt.timeout[stage] = value; + } + break; + } + case A_TIMG_WDTFEED: + if (!esp32_timg_wdt_protected(&s->wdt)) { + esp32_timg_wdt_feed(&s->wdt); + } + break; + case A_TIMG_WDTPROTECT: + s->wdt.protect_reg = value; + break; + + + case A_TIMG_RTCCALICFG: + s->rtc_cal_start = FIELD_EX32(value, TIMG_RTCCALICFG, START); + s->rtc_cal_ready = FIELD_EX32(value, TIMG_RTCCALICFG, RDY); + s->rtc_cal_clk_sel = FIELD_EX32(value, TIMG_RTCCALICFG, CLK_SEL); + s->rtc_cal_max = FIELD_EX32(value, TIMG_RTCCALICFG, MAX); + esp32_timg_do_calibration(s); + break; + + case A_TIMG_INT_ENA: + s->int_ena = value; + esp32_timg_int_update(s); + break; + case A_TIMG_INT_CLR: + s->int_raw &= ~value; + esp32_timg_int_update(s); + break; + } +} + +static const MemoryRegionOps esp32_timg_ops = { + .read = esp32_timg_read, + .write = esp32_timg_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_timg_timer_reset(Esp32TimgTimerState* ts) +{ + timer_del(&ts->alarm_timer); + ts->config_reg = R_TIMG_T0CONFIG_INCREASE_MASK + | R_TIMG_T0CONFIG_AUTORELOAD_MASK + | (1 << R_TIMG_T0CONFIG_DIVIDER_SHIFT); + ts->alarm_val = 0; + ts->load_val = 0; + ts->count_base = 0; + ts->ns_base = 0; + esp32_timg_timer_update_config(ts); +} + +static void esp32_timg_wdt_reset(Esp32TimgWdtState* ws) +{ + timer_del(&ws->stage_timer); + + ws->config0_reg = 0x0004c000; + ws->config1_reg = 0x00010000; + ws->timeout[0] = 0x018cba80; + ws->timeout[1] = 0x07ffffff; + ws->timeout[2] = 0x000fffff; + ws->timeout[3] = 0x000fffff; + ws->protect_reg = ESP32_TIMG_WDT_PROTECT_WORD; + + if (ws->parent->wdt_en_at_reset) { + /* On reset, stage0 is configured as system reset, however this is done by + * hardware state, not in config0 register. Emulate this by temporarily setting STG0 field here. + */ + ws->config0_reg |= (WDT_MODE_SYSRESET << R_TIMG_WDTCONFIG0_STG0_SHIFT); + } + esp32_timg_wdt_update_config(ws); + if (ws->parent->wdt_en_at_reset) { + ws->config0_reg &= (~R_TIMG_WDTCONFIG0_STG0_MASK); + } +} + +static void esp32_timg_reset(DeviceState *dev) +{ + Esp32TimgState *s = ESP32_TIMG(dev); + s->rtc_cal_max = 1; + s->rtc_cal_clk_sel = ESP32_TIMG_CAL_8MD256; + s->rtc_cal_ready = 0; + s->rtc_cal_start = 1; + esp32_timg_do_calibration(s); + + esp32_timg_timer_reset(&s->t0); + esp32_timg_timer_reset(&s->t1); + esp32_timg_timer_reset(&s->lact); + esp32_timg_wdt_reset(&s->wdt); +} + +static void esp32_timg_set_apb_freq(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + Esp32TimgState *s = ESP32_TIMG(opaque); + visit_type_uint32(v, name, &s->apb_freq_hz, errp); + TIMG_DEBUG_LOG("%s: TG%d apb_freq_hz=%d\n", __func__, s->id, s->apb_freq_hz); +} + +static void esp32_timg_do_calibration(Esp32TimgState* s) +{ + uint32_t cal_clk_freq; + if (s->rtc_cal_clk_sel == ESP32_TIMG_CAL_RTC_MUX) { + cal_clk_freq = s->rtc_slow_freq_hz; + } else if (s->rtc_cal_clk_sel == ESP32_TIMG_CAL_32K_XTAL) { + cal_clk_freq = 32768; + } else { + cal_clk_freq = 8000000 / 256; + } + + s->rtc_cal_value = muldiv64(s->xtal_freq_hz, s->rtc_cal_max, cal_clk_freq); + s->rtc_cal_ready = true; +} + +static void esp32_timg_timer_cb(void *opaque) +{ + Esp32TimgTimerState *ts = (Esp32TimgTimerState*) opaque; + Esp32TimgState *s = ts->parent; + uint64_t ns_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + TIMG_DEBUG_LOG("%s: TG%d ns=0x%llx\n", __func__, s->id, ns_now); + uint32_t int_mask = 1 << (ts->int_type); + + if (ts->level_int_en) { + s->int_raw |= int_mask; + if (s->int_ena & int_mask) { + qemu_irq_raise(get_level_irq(s, ts->int_type)); + } + } + + if (ts->edge_int_en) { + if (s->int_ena & int_mask) { + qemu_irq_pulse(get_edge_irq(s, ts->int_type)); + } + } + + ts->alarm = false; + + if (ts->autoreload) { + esp32_timg_timer_reload(ts, ns_now); + } else { + /* ignore overflow modulo 64 bits */ + timer_del(&ts->alarm_timer); + } +} + +static void esp32_timg_int_update_inttype(Esp32TimgState *s, uint32_t int_st, Esp32TimgInterruptType it) +{ + if (int_st & (1 << it)) { + qemu_irq_raise(get_level_irq(s, it)); + } else { + qemu_irq_lower(get_level_irq(s, it)); + } +} + +static void esp32_timg_int_update(Esp32TimgState *s) +{ + uint32_t int_st = s->int_ena & s->int_raw; + esp32_timg_int_update_inttype(s, int_st, TIMG_T0_INT); + esp32_timg_int_update_inttype(s, int_st, TIMG_T1_INT); + esp32_timg_int_update_inttype(s, int_st, TIMG_WDT_INT); + esp32_timg_int_update_inttype(s, int_st, TIMG_LACT_INT); +} + +static int esp32_timg_timer_direction(Esp32TimgTimerState *s) +{ + if (!s->en) { + return 0; + } + if (s->inc) { + return 1; + } else { + return -1; + } +} + +static uint64_t esp32_timg_timer_get_count(Esp32TimgTimerState *s, uint64_t ns_now) +{ + if (!s->en) { + return s->count_base; + } + uint64_t ns_from_base = ns_now - s->ns_base; + uint64_t ticks_from_base = muldiv64(ns_from_base, s->parent->apb_freq_hz / 1000000, 1000 * s->divider); + uint64_t count = esp32_timg_timer_direction(s) * ticks_from_base + s->count_base; + return count; +} + +static uint64_t esp32_timg_timer_count_to_ns(Esp32TimgTimerState *s, uint64_t count) +{ + return muldiv64(count, 1000 * s->divider, s->parent->apb_freq_hz / 1000000); +} + +static uint32_t esp32_timg_timer_div_from_reg(uint32_t reg_val) +{ + if (reg_val == 0) { + return 65536; + } + if (reg_val == 1 || reg_val == 2) { + return 2; + } + return reg_val; +} + +static void esp32_timg_timer_update_config(Esp32TimgTimerState *ts) +{ + uint64_t ns_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + ts->count_base = esp32_timg_timer_get_count(ts, ns_now); + ts->ns_base = ns_now; + + ts->en = FIELD_EX32(ts->config_reg, TIMG_T0CONFIG, EN); + ts->inc = FIELD_EX32(ts->config_reg, TIMG_T0CONFIG, INCREASE); + ts->autoreload = FIELD_EX32(ts->config_reg, TIMG_T0CONFIG, AUTORELOAD); + ts->divider = esp32_timg_timer_div_from_reg(FIELD_EX32(ts->config_reg, TIMG_T0CONFIG, DIVIDER)); + ts->edge_int_en = FIELD_EX32(ts->config_reg, TIMG_T0CONFIG, EDGE_INT); + ts->level_int_en = FIELD_EX32(ts->config_reg, TIMG_T0CONFIG, LEVEL_INT); + ts->alarm = FIELD_EX32(ts->config_reg, TIMG_T0CONFIG, ALARM); + + TIMG_DEBUG_LOG("%s: TG%d base=0x%llx ns=0x%llx en=%d inc=%d autoreload=%d div=%d li=%d ei=%d alarm=%d\n", __func__, ts->parent->id, + ts->count_base, ts->ns_base, ts->en, ts->inc, ts->autoreload, ts->divider, + ts->level_int_en, ts->edge_int_en, ts->alarm); + + esp32_timg_timer_update_alarm(ts, ns_now); +} + +static void esp32_timg_timer_reload(Esp32TimgTimerState *ts, uint64_t ns_now) +{ + timer_del(&ts->alarm_timer); + + ts->ns_base = ns_now; + ts->count_base = ts->load_val; + + TIMG_DEBUG_LOG("%s: TG%d base=0x%llx ns=0x%llx\n", __func__, ts->parent->id, + ts->count_base, ts->ns_base); + + esp32_timg_timer_update_alarm(ts, ns_now); +} + +static void esp32_timg_timer_update_alarm(Esp32TimgTimerState *ts, uint64_t ns_now) +{ + if (!ts->en || !ts->alarm) { + timer_del(&ts->alarm_timer); + return; + } + + int64_t count_to_alarm = ((int64_t) ts->alarm_val - (int64_t) ts->count_base) + * esp32_timg_timer_direction(ts); + if (count_to_alarm <= 0) { + /* ignore overflow modulo 64 bits */ + timer_del(&ts->alarm_timer); + return; + } + + uint64_t ns_to_alarm = esp32_timg_timer_count_to_ns(ts, count_to_alarm); + + TIMG_DEBUG_LOG("%s: TG%d count_to_alarm=0x%llx ns_to_alarm=0x%llx\n", __func__, ts->parent->id, + count_to_alarm, ns_to_alarm); + + timer_mod_anticipate_ns(&ts->alarm_timer, ns_now + ns_to_alarm); +} + +static bool esp32_timg_wdt_protected(Esp32TimgWdtState *ws) +{ + return ws->protect_reg != ESP32_TIMG_WDT_PROTECT_WORD; +} + +static uint64_t esp32_timg_wdt_get_count(Esp32TimgWdtState *ws, uint64_t ns_now) +{ + if (!ws->en) { + return ws->count_base; + } + uint64_t ns_from_base = ns_now - ws->ns_base; + uint64_t ticks_from_base = muldiv64(ns_from_base, ws->parent->apb_freq_hz / 1000000, 1000 * MAX(ws->prescale, 1)); + uint64_t count = ticks_from_base + ws->count_base; + return count; +} + +static void esp32_timg_wdt_update_config(Esp32TimgWdtState *ws) +{ + Esp32TimgState *s = ws->parent; + + uint64_t ns_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + ws->count_base = esp32_timg_wdt_get_count(ws, ns_now); + ws->ns_base = ns_now; + + bool old_en = ws->en; + ws->en = FIELD_EX32(ws->config0_reg, TIMG_WDTCONFIG0, EN); + ws->mode[0] = FIELD_EX32(ws->config0_reg, TIMG_WDTCONFIG0, STG0); + ws->mode[1] = FIELD_EX32(ws->config0_reg, TIMG_WDTCONFIG0, STG1); + ws->mode[2] = FIELD_EX32(ws->config0_reg, TIMG_WDTCONFIG0, STG2); + ws->mode[3] = FIELD_EX32(ws->config0_reg, TIMG_WDTCONFIG0, STG3); + ws->edge_int_en = FIELD_EX32(ws->config0_reg, TIMG_WDTCONFIG0, EDGE_INT); + ws->level_int_en = FIELD_EX32(ws->config0_reg, TIMG_WDTCONFIG0, LEVEL_INT); + ws->flashboot_en = FIELD_EX32(ws->config0_reg, TIMG_WDTCONFIG0, FLASHBOOT_MODE_EN); + + ws->prescale = FIELD_EX32(ws->config1_reg, TIMG_WDTCONFIG1, PRESCALE); + + if (ws->en && !old_en) { + ws->cur_stage = 0; + ws->count_base = 0; + } else if (!ws->en && old_en) { + qemu_irq_lower(get_level_irq(s, TIMG_WDT_INT)); + } + + TIMG_DEBUG_LOG("%s: TG%d config 0x%08x prescale=0x%08x en=%d fb_en=%d level_int_en=%d\n", __func__, ws->parent->id, + ws->config0_reg, ws->prescale, ws->en, ws->flashboot_en, ws->level_int_en); + esp32_timg_wdt_arm(ws, ns_now); +} + +static void esp32_timg_wdt_feed(Esp32TimgWdtState *ws) +{ + TIMG_DEBUG_LOG("%s TG%d\n", __func__, ws->parent->id); + uint64_t ns_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + ws->cur_stage = 0; + ws->ns_base = ns_now; + ws->count_base = 0; + esp32_timg_wdt_arm(ws, ns_now); +} + +static void esp32_timg_wdt_arm(Esp32TimgWdtState *ws, uint64_t ns_now) +{ + timer_del(&ws->stage_timer); + + if (ws->parent->wdt_disable || !(ws->en || (ws->flashboot_en && ws->parent->flash_boot_mode))) { + return; + } + + uint32_t stage_timeout = ws->timeout[ws->cur_stage]; + uint32_t cur_count = esp32_timg_wdt_get_count(ws, ns_now); + uint32_t count_to_timeout = stage_timeout - cur_count; + uint64_t ns_to_timeout = muldiv64(count_to_timeout, 1000 * ws->prescale, ws->parent->apb_freq_hz / 1000000); + TIMG_DEBUG_LOG("%s: TG%d ns=0x%08llx stage %d count=0x%08x count_to_timeout=0x%08x ns_to_timeout=0x%08llx\n", + __func__, ws->parent->id, ns_now, ws->cur_stage, cur_count, count_to_timeout, ns_to_timeout); + timer_mod_anticipate_ns(&ws->stage_timer, ns_now + ns_to_timeout); +} + +static void esp32_timg_wdt_cb(void *opaque) +{ + Esp32TimgWdtState *ws = (Esp32TimgWdtState*) opaque; + Esp32TimgState *s = ws->parent; + Esp32TimgWdtStageMode mode = ws->mode[ws->cur_stage]; + TIMG_DEBUG_LOG("%s: TG%d stage %d timeout mode %d\n", __func__, s->id, ws->cur_stage, mode); + if (mode == WDT_MODE_INT) { + uint32_t mask = 1 << TIMG_WDT_INT; + if (ws->level_int_en) { + s->int_raw |= mask; + if (true) { /* should be checking s->int_ena & mask, but ESP32 seems to raise interrupt regardless? */ + qemu_irq_raise(get_level_irq(s, TIMG_WDT_INT)); + } + } + if (ws->edge_int_en) { + if (s->int_ena & mask) { + qemu_irq_pulse(get_edge_irq(s, TIMG_WDT_INT)); + } + } + } else if (mode == WDT_MODE_CPURESET) { + qemu_irq_pulse(s->wdt_cpu_reset_req); + } else if (mode == WDT_MODE_SYSRESET) { + qemu_irq_pulse(s->wdt_sys_reset_req); + } + + int next_stage = (ws->cur_stage + 1) % ESP32_TIMG_WDT_STAGE_COUNT; + uint64_t ns_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + ws->count_base = 0; + ws->cur_stage = next_stage; + ws->ns_base = ns_now; + esp32_timg_wdt_arm(ws, ns_now); +} + +static void esp32_timg_realize(DeviceState *dev, Error **errp) +{ +} + +static void esp32_timg_timer_init(Esp32TimgState *s, Esp32TimgTimerState *ts, Esp32TimgInterruptType int_type) { + ts->parent = s; + timer_init_ns(&ts->alarm_timer, QEMU_CLOCK_VIRTUAL, esp32_timg_timer_cb, ts); + ts->int_type = int_type; +} + +static void esp32_timg_init(Object *obj) +{ + Esp32TimgState *s = ESP32_TIMG(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_timg_ops, s, + TYPE_ESP32_TIMG, TIMG_REGFILE_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + qdev_init_gpio_out_named(DEVICE(sbd), s->irqs, SYSBUS_DEVICE_GPIO_IRQ, 2*TIMG_INT_MAX); + + object_property_add(obj, "apb_freq", "uint32", + NULL, + esp32_timg_set_apb_freq, + NULL, + obj); + + s->rtc_slow_freq_hz = 150000; + s->xtal_freq_hz = 40000000; + s->apb_freq_hz = 40000000; + + esp32_timg_timer_init(s, &s->t0, TIMG_T0_INT); + esp32_timg_timer_init(s, &s->t1, TIMG_T1_INT); + esp32_timg_timer_init(s, &s->lact, TIMG_LACT_INT); + + s->wdt.parent = s; + timer_init_ns(&s->wdt.stage_timer, QEMU_CLOCK_VIRTUAL, esp32_timg_wdt_cb, &s->wdt); + qdev_init_gpio_out_named(DEVICE(sbd), &s->wdt_cpu_reset_req, ESP32_TIMG_WDT_CPU_RESET_GPIO, 1); + qdev_init_gpio_out_named(DEVICE(sbd), &s->wdt_sys_reset_req, ESP32_TIMG_WDT_SYS_RESET_GPIO, 1); +} + +static Property esp32_timg_properties[] = { + DEFINE_PROP_BOOL("wdt_disable", Esp32TimgState, wdt_disable, false), + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32_timg_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32_timg_reset; + dc->realize = esp32_timg_realize; + device_class_set_props(dc, esp32_timg_properties); +} + +static const TypeInfo esp32_timg_info = { + .name = TYPE_ESP32_TIMG, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32TimgState), + .instance_init = esp32_timg_init, + .class_init = esp32_timg_class_init +}; + +static void esp32_timg_register_types(void) +{ + type_register_static(&esp32_timg_info); +} + +type_init(esp32_timg_register_types) diff --git a/hw/timer/esp32c3_systimer.c b/hw/timer/esp32c3_systimer.c new file mode 100644 index 000000000000..c3856561ec29 --- /dev/null +++ b/hw/timer/esp32c3_systimer.c @@ -0,0 +1,603 @@ +/* + * ESP32-C3 System Timer + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "qapi/visitor.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/registerfields.h" +#include "hw/boards.h" +#include "hw/timer/esp32c3_systimer.h" + + +#define TICKS_TO_NS(ticks) (((ticks) / ESP32C3_SYSTIMER_CNT_PER_US) * 1000) + +#define SYSTIMER_DEBUG 0 +#define SYSTIMER_WARNING 0 + +/** + * @brief Update the value of a counter according the QEMU virtual timer. + */ +static void esp32c3_systimer_update_counter(ESP32C3SysTimerCounter *counter) { + const int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + const int64_t elapsed_ns = now - counter->base; + const int64_t ticks = (elapsed_ns * (ESP32C3_SYSTIMER_CNT_CLK / 1000000)) / 1000; + counter->value = (counter->value + ticks) & ESP32C3_SYSTIMER_52BIT_MASK; + counter->base = now; +} + + +static void esp32c3_systimer_set_irqs(ESP32C3SysTimerState *s) +{ + for (int i = 0; i < ESP32C3_SYSTIMER_COMP_COUNT; i++) { + ESP32C3SysTimerComp* comparator = &s->comparators[i]; + /* Optimize a bit by not calling the interrupt module if the state didn't change */ + const int new_level = comparator->raw_st && comparator->int_enabled; + if (new_level != comparator->cur_irq_level) { + comparator->cur_irq_level = new_level; + qemu_set_irq(comparator->irq, new_level); + } + } +} + + +static void esp32c3_systimer_notify(ESP32C3SysTimerComp* comparator) +{ + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +#if SYSTIMER_DEBUG + static int64_t previous = 0; + info_report("Elapsed since last interrupt %ld ns\n", now - previous); + previous = now; +#endif + + /* Update the counter linked to the comparator */ + const uint32_t counter_idx = comparator->counter; + ESP32C3SysTimerState *s = comparator->systimer; + ESP32C3SysTimerCounter* counter = &s->counter[counter_idx]; + + if (counter->enabled) { + esp32c3_systimer_update_counter(counter); + } + + /* Set the IRQ line if anything changed */ + comparator->cur_irq_level = 1; + qemu_irq_raise(comparator->irq); + + /* Check if we have to reload the comparator's timer */ + if (counter->enabled && comparator->period_mode) { + /** + * If the timer is periodic, we have to compensate the delay that may have been taken + * by QEMU framework. Indeed, this timer may have been triggered too late (tenth of us) + * As such, compensate here by triggering the next timer earlier. + */ + const int64_t diff_ns = now - comparator->expire_time; + const int64_t target_ns = now + TICKS_TO_NS(comparator->period); + int64_t adjusted_target_ns = target_ns; + + if (diff_ns < target_ns) { + adjusted_target_ns = target_ns - diff_ns; + } + + comparator->expire_time = adjusted_target_ns; + timer_mod_ns(&comparator->qtimer, adjusted_target_ns); + } +} + + +/** + * @brief Function called when the configuration of the given comparator changed. + * It will reprogram the QEMU Timer according to the new parameters. The comparator + * must be enabled when this function is called. + */ +static void esp32c3_systimer_comparator_reprogram(ESP32C3SysTimerComp* comparator) +{ + assert(comparator->enabled); + + const uint32_t counter_idx = comparator->counter; + ESP32C3SysTimerState *s = comparator->systimer; + ESP32C3SysTimerCounter* counter = &s->counter[counter_idx]; + + /* Update the counter to get the latest value */ + esp32c3_systimer_update_counter(counter); + + /* If the counter we have to compare it to is not enabled, do not program any timer */ + if (!counter->enabled) { + /* "Disable" the timer */ + timer_del(&comparator->qtimer); + return; + } + + /** + * According to the TRM, if the comparator (alarm) is smaller than the counter value and the + * difference is bigger or equal to (2^51) - 1, the alarm is not triggered right now and the counter + * will have to overflow first before reached the comparator value. + */ + const int64_t count_val = counter->value; + const int64_t alarm = comparator->value; + const bool overflow_valid = alarm < count_val && count_val - alarm >= ((1ULL << 51) - 1); + + if (!comparator->period_mode && !overflow_valid && alarm <= count_val) { + timer_del(&comparator->qtimer); + esp32c3_systimer_notify(comparator); + return; + } + + /* Calculate in how many ns the counter would reach the comparator */ + uint64_t diff = 0; + + if (comparator->period_mode) { + diff = comparator->period; + } else if (overflow_valid) { + diff = ((ESP32C3_SYSTIMER_52BIT_MASK + 1) - count_val) + alarm; + } else { + diff = alarm - count_val; + } + + /* Calculate the number of ns the counter will take to reach the absolute count */ + const int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + const int64_t target_ns = now + TICKS_TO_NS(diff); + comparator->expire_time = target_ns; + timer_mod_ns(&comparator->qtimer, target_ns); +} + + +static uint32_t esp32c3_systimer_comparator_get_conf(ESP32C3SysTimerComp *comp) +{ + uint32_t reg = comp->period & R_SYSTIMER_TARGET0_CONF_PERIOD_MASK; + reg |= (comp->period_mode << R_SYSTIMER_TARGET0_CONF_PERIOD_MODE_SHIFT) & R_SYSTIMER_TARGET0_CONF_PERIOD_MODE_MASK; + reg |= (comp->counter << R_SYSTIMER_TARGET0_CONF_TIMER_UNIT_SEL_SHIFT) & R_SYSTIMER_TARGET0_CONF_TIMER_UNIT_SEL_MASK; + return reg; +} + + +static uint64_t esp32c3_systimer_read(void *opaque, hwaddr addr, unsigned int size) +{ + ESP32C3SysTimerState *s = ESP32C3_SYSTIMER(opaque); + uint64_t r = 0; + + switch (addr) { + case A_SYSTIMER_CONF: + r = s->conf; + break; + case A_SYSTIMER_UNIT0_OP: + case A_SYSTIMER_UNIT1_OP: + /* Value is always synchronized and valid */ + r = R_SYSTIMER_UNIT0_OP_VALUE_VALID_MASK; + break; + + /* Registers linked to UNIT0 registers */ + case A_SYSTIMER_UNIT0_VALUE_HI: + r = SYSTIMER_GET_REG(s->counter[0].flushed, 32, R_SYSTIMER_UNIT0_VALUE_HI_TIMER_HI_MASK); + break; + case A_SYSTIMER_UNIT0_VALUE_LO: + r = SYSTIMER_GET_REG(s->counter[0].flushed, 0, R_SYSTIMER_UNIT0_VALUE_LO_TIMER_LO_MASK); + break; + case A_SYSTIMER_UNIT0_LOAD_HI: + r = SYSTIMER_GET_REG(s->counter[0].toload, 32, R_SYSTIMER_UNIT0_LOAD_HI_HI_MASK); + break; + case A_SYSTIMER_UNIT0_LOAD_LO: + r = SYSTIMER_GET_REG(s->counter[0].toload, 0, R_SYSTIMER_UNIT0_LOAD_LO_LO_MASK); + break; + + /* Same for UNIT1 */ + case A_SYSTIMER_UNIT1_VALUE_HI: + r = SYSTIMER_GET_REG(s->counter[1].flushed, 32, R_SYSTIMER_UNIT1_VALUE_HI_TIMER_HI_MASK); + break; + case A_SYSTIMER_UNIT1_VALUE_LO: + r = SYSTIMER_GET_REG(s->counter[1].flushed, 0, R_SYSTIMER_UNIT1_VALUE_LO_TIMER_LO_MASK); + break; + case A_SYSTIMER_UNIT1_LOAD_HI: + r = SYSTIMER_GET_REG(s->counter[1].toload, 32, R_SYSTIMER_UNIT1_LOAD_HI_HI_MASK); + break; + case A_SYSTIMER_UNIT1_LOAD_LO: + r = SYSTIMER_GET_REG(s->counter[1].toload, 0, R_SYSTIMER_UNIT1_LOAD_LO_LO_MASK); + break; + + /* Read back the value of the comparators */ + case A_SYSTIMER_TARGET0_HI: + r = SYSTIMER_GET_REG(s->comparators[0].value_toload, 32, R_SYSTIMER_TARGET0_HI_HI_MASK); + break; + case A_SYSTIMER_TARGET0_LO: + r = SYSTIMER_GET_REG(s->comparators[0].value_toload, 0, R_SYSTIMER_TARGET0_LO_LO_MASK); + break; + case A_SYSTIMER_TARGET0_CONF: + r = esp32c3_systimer_comparator_get_conf(&s->comparators[0]); + break; + + /* Registers linked to Comparator 1 */ + case A_SYSTIMER_TARGET1_HI: + r = SYSTIMER_GET_REG(s->comparators[1].value_toload, 32, R_SYSTIMER_TARGET1_HI_HI_MASK); + break; + case A_SYSTIMER_TARGET1_LO: + r = SYSTIMER_GET_REG(s->comparators[1].value_toload, 0, R_SYSTIMER_TARGET1_LO_LO_MASK); + break; + case A_SYSTIMER_TARGET1_CONF: + r = esp32c3_systimer_comparator_get_conf(&s->comparators[1]); + break; + + /* Registers linked to Comparator 2 */ + case A_SYSTIMER_TARGET2_HI: + r = SYSTIMER_GET_REG(s->comparators[2].value_toload, 32, R_SYSTIMER_TARGET2_HI_HI_MASK); + break; + case A_SYSTIMER_TARGET2_LO: + r = SYSTIMER_GET_REG(s->comparators[2].value_toload, 0, R_SYSTIMER_TARGET2_LO_LO_MASK); + break; + case A_SYSTIMER_TARGET2_CONF: + r = esp32c3_systimer_comparator_get_conf(&s->comparators[2]); + break; + + /* Interrupt related */ + case A_SYSTIMER_INT_RAW: + r = s->comparators[0].raw_st << R_SYSTIMER_INT_RAW_TARGET0_SHIFT + | s->comparators[1].raw_st << R_SYSTIMER_INT_RAW_TARGET1_SHIFT + | s->comparators[2].raw_st << R_SYSTIMER_INT_RAW_TARGET2_SHIFT; + break; + + case A_SYSTIMER_INT_ENA: + r = s->comparators[0].int_enabled << R_SYSTIMER_INT_ENA_TARGET0_SHIFT + | s->comparators[1].int_enabled << R_SYSTIMER_INT_ENA_TARGET1_SHIFT + | s->comparators[2].int_enabled << R_SYSTIMER_INT_ENA_TARGET2_SHIFT; + break; + + case A_SYSTIMER_INT_ST: + r = (s->comparators[0].raw_st & s->comparators[0].int_enabled) << R_SYSTIMER_INT_ST_TARGET0_SHIFT + | (s->comparators[1].raw_st & s->comparators[1].int_enabled) << R_SYSTIMER_INT_ST_TARGET1_SHIFT + | (s->comparators[2].raw_st & s->comparators[2].int_enabled) << R_SYSTIMER_INT_ST_TARGET2_SHIFT; + break; + + case A_SYSTIMER_INT_CLR: + /* This register is read-only */ + break; + + default: +#if SYSTIMER_WARNING + warn_report("[SYSTIMER] Unsupported read to %08lx\n", addr); +#endif + break; + } + +#if SYSTIMER_DEBUG + info_report("[SYSTIMER] Reading from %08lx (%08lx)\n", addr, r); +#endif + return r; +} + +/** + * @brief Function called when a guest program requests a flush of the internal + * counter inside a mirror register: `flushed`. + */ +static void esp32c3_systimer_flush_counter(ESP32C3SysTimerCounter *counter) +{ + /* If the counter is enabled, get its latest value */ + if (counter->enabled) { + esp32c3_systimer_update_counter(counter); + } + /* In any case, flush the value to send to the guest program */ + counter->flushed = counter->value; +} + +/** + * @brief Function called when the guest programs wants to replace the value + * of the given counter + */ +static void esp32c3_systimer_load_counter(ESP32C3SysTimerState *s, uint32_t index) +{ + ESP32C3SysTimerCounter* counter = &s->counter[index]; + + /* If the counter is enabled, update the internal value to the latest count. + * Even though the value will be replaced, this will also update the base time. */ + if (counter->enabled) { + esp32c3_systimer_update_counter(counter); + } + counter->value = counter->toload; + + /* If one of the comparator is enabled and depends on the current timer, reprogram it */ + for (int i = 0; i < ESP32C3_SYSTIMER_COMP_COUNT; i++) { + if (s->comparators[i].enabled && s->comparators[i].counter == index) { + esp32c3_systimer_comparator_reprogram(&s->comparators[i]); + } + } +} + + +static void esp32c3_systimer_comparator_conf(ESP32C3SysTimerComp* comparator, uint64_t value) +{ + uint32_t old_counter = comparator->counter; + comparator->period_mode = (value & R_SYSTIMER_TARGET0_CONF_PERIOD_MODE_MASK) ? 1 : 0; + comparator->counter = (value & R_SYSTIMER_TARGET0_CONF_TIMER_UNIT_SEL_MASK) ? 1 : 0; + comparator->period_toload = value & R_SYSTIMER_TARGET0_CONF_PERIOD_MASK; + + /* If the comparator is enabled while the counter to compare it to changed, reload the timer! */ + if (comparator->enabled && old_counter != comparator->counter) { + esp32c3_systimer_comparator_reprogram(comparator); + } +} + + +static void esp32c3_systimer_comparator_reload(ESP32C3SysTimerComp* comparator) +{ + comparator->period = comparator->period_toload; + comparator->value = comparator->value_toload; + + if (comparator->enabled) { + /* The period changed, reprogram the QEMU timer */ + esp32c3_systimer_comparator_reprogram(comparator); + } +} + + +static void esp32c3_systimer_conf_set(ESP32C3SysTimerState *s, uint64_t value) +{ + bool state[ESP32C3_SYSTIMER_COMP_COUNT] = { 0 }; + bool state_counter[ESP32C3_SYSTIMER_COUNTER_COUNT] = { 0 }; + + for (int i = 0; i < ESP32C3_SYSTIMER_COUNTER_COUNT; i++) { + state_counter[i] = s->counter[i].enabled; + } + s->counter[0].enabled = (value & R_SYSTIMER_CONF_TIMER_UNIT0_WORK_EN_MASK) ? 1 : 0; + s->counter[1].enabled = (value & R_SYSTIMER_CONF_TIMER_UNIT1_WORK_EN_MASK) ? 1 : 0; + s->counter[0].enabled_on_stall = (value & R_SYSTIMER_CONF_TIMER_UNIT0_CORE0_STALL_EN_MASK) ? 1 : 0; + s->counter[1].enabled_on_stall = (value & R_SYSTIMER_CONF_TIMER_UNIT1_CORE0_STALL_EN_MASK) ? 1 : 0; + + /* If the state of the counter changed while one of the comparator depends on it, reload it */ + for (int i = 0; i < ESP32C3_SYSTIMER_COMP_COUNT; i++) { + const int count_idx = s->comparators[i].counter; + + if (s->comparators[i].enabled && state_counter[count_idx] != s->counter[count_idx].enabled) { + esp32c3_systimer_comparator_reprogram(&s->comparators[i]); + } + } + + + /** + * Do the same thing for the comparators: assign the new state while checking if a change occurred, + * if that's the case, reprogram it. + */ + for (int i = 0; i < ESP32C3_SYSTIMER_COMP_COUNT; i++) { + state[i] = s->comparators[i].enabled; + } + + s->comparators[0].enabled = (value & R_SYSTIMER_CONF_TARGET0_WORK_EN_MASK) ? 1 : 0; + s->comparators[1].enabled = (value & R_SYSTIMER_CONF_TARGET1_WORK_EN_MASK) ? 1 : 0; + s->comparators[2].enabled = (value & R_SYSTIMER_CONF_TARGET2_WORK_EN_MASK) ? 1 : 0; + + for (int i = 0; i < ESP32C3_SYSTIMER_COMP_COUNT; i++) { + if (state[i] == s->comparators[i].enabled) { + continue; + } + + /* If the comparator has just been enabled, (re)program it. + * If it was enabled and it is now disabled, disable the QEMU timer. */ + if (s->comparators[i].enabled) { + esp32c3_systimer_comparator_reprogram(&s->comparators[i]); + } else { + timer_del(&s->comparators[i].qtimer); + } + } + + /* Ignore R_SYSTIMER_CONF_CLK_EN */ + s->conf = (uint32_t) value; +} + + +static void esp32c3_systimer_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + ESP32C3SysTimerState *s = ESP32C3_SYSTIMER(opaque); + (void) s; + + switch(addr) { + case A_SYSTIMER_CONF: + esp32c3_systimer_conf_set(s, value); + break; + case A_SYSTIMER_UNIT0_OP: + case A_SYSTIMER_UNIT1_OP: + /* Check if an update was requested on one of the timers */ + if (value & R_SYSTIMER_UNIT0_OP_UPDATE_MASK) { + /* Address is either 4 (unit0) or 8 (unit 1), get index by dividing by 8 */ + esp32c3_systimer_flush_counter(&s->counter[addr / 8]); + } + break; + + /* Registers linked to UNIT0 registers */ + case A_SYSTIMER_UNIT0_LOAD_HI: + systimer_set_reg(&s->counter[0].toload, value, R_SYSTIMER_UNIT0_LOAD_HI_HI_MASK, 32); + break; + case A_SYSTIMER_UNIT0_LOAD_LO: + systimer_set_reg(&s->counter[0].toload, value, R_SYSTIMER_UNIT0_LOAD_LO_LO_MASK, 0); + break; + case A_SYSTIMER_UNIT0_LOAD: + esp32c3_systimer_load_counter(s, 0); + break; + + /* Registers linked to UNIT1 registers */ + case A_SYSTIMER_UNIT1_LOAD_HI: + systimer_set_reg(&s->counter[1].toload, value, R_SYSTIMER_UNIT1_LOAD_HI_HI_MASK, 32); + break; + case A_SYSTIMER_UNIT1_LOAD_LO: + systimer_set_reg(&s->counter[1].toload, value, R_SYSTIMER_UNIT1_LOAD_LO_LO_MASK, 0); + break; + case A_SYSTIMER_UNIT1_LOAD: + esp32c3_systimer_load_counter(s, 1); + break; + + /* Registers linked to Comparator 0 */ + case A_SYSTIMER_TARGET0_HI: + systimer_set_reg(&s->comparators[0].value_toload, value, R_SYSTIMER_TARGET0_HI_HI_MASK, 32); + break; + case A_SYSTIMER_TARGET0_LO: + systimer_set_reg(&s->comparators[0].value_toload, value, R_SYSTIMER_TARGET0_LO_LO_MASK, 0); + break; + case A_SYSTIMER_TARGET0_CONF: + esp32c3_systimer_comparator_conf(&s->comparators[0], value); + break; + case A_SYSTIMER_COMP0_LOAD: + if (value & R_SYSTIMER_COMP0_LOAD_LOAD_MASK) { + esp32c3_systimer_comparator_reload(&s->comparators[0]); + } + break; + + /* Registers linked to Comparator 1 */ + case A_SYSTIMER_TARGET1_HI: + systimer_set_reg(&s->comparators[1].value_toload, value, R_SYSTIMER_TARGET1_HI_HI_MASK, 32); + break; + case A_SYSTIMER_TARGET1_LO: + systimer_set_reg(&s->comparators[1].value_toload, value, R_SYSTIMER_TARGET1_LO_LO_MASK, 0); + break; + case A_SYSTIMER_TARGET1_CONF: + esp32c3_systimer_comparator_conf(&s->comparators[1], value); + break; + case A_SYSTIMER_COMP1_LOAD: + if (value & R_SYSTIMER_COMP1_LOAD_LOAD_MASK) { + esp32c3_systimer_comparator_reload(&s->comparators[1]); + } + break; + + /* Registers linked to Comparator 2 */ + case A_SYSTIMER_TARGET2_HI: + systimer_set_reg(&s->comparators[2].value_toload, value, R_SYSTIMER_TARGET2_HI_HI_MASK, 32); + break; + case A_SYSTIMER_TARGET2_LO: + systimer_set_reg(&s->comparators[2].value_toload, value, R_SYSTIMER_TARGET2_LO_LO_MASK, 0); + break; + case A_SYSTIMER_TARGET2_CONF: + esp32c3_systimer_comparator_conf(&s->comparators[2], value); + break; + case A_SYSTIMER_COMP2_LOAD: + if (value & R_SYSTIMER_COMP2_LOAD_LOAD_MASK) { + esp32c3_systimer_comparator_reload(&s->comparators[2]); + } + break; + + /* Interrupt related */ + case A_SYSTIMER_INT_RAW: + case A_SYSTIMER_INT_ST: +#if SYSTIMER_WARNING + warn_report("[SYSTIMER] Unsupported write to INT RAW/ST registers\n"); +#endif + break; + + case A_SYSTIMER_INT_ENA: + s->comparators[0].int_enabled = FIELD_EX32(value, SYSTIMER_INT_ENA, TARGET0); + s->comparators[1].int_enabled = FIELD_EX32(value, SYSTIMER_INT_ENA, TARGET1); + s->comparators[2].int_enabled = FIELD_EX32(value, SYSTIMER_INT_ENA, TARGET2); + esp32c3_systimer_set_irqs(s); + break; + + case A_SYSTIMER_INT_CLR: + /* The formula (RAW & !CLR) results in 0 if both CLR and RAW were 1, else it keeps + * RAW unchanged. */ + s->comparators[0].raw_st &= ! FIELD_EX32(value, SYSTIMER_INT_CLR, TARGET0); + s->comparators[1].raw_st &= ! FIELD_EX32(value, SYSTIMER_INT_CLR, TARGET1); + s->comparators[2].raw_st &= ! FIELD_EX32(value, SYSTIMER_INT_CLR, TARGET2); + esp32c3_systimer_set_irqs(s); + break; + + default: +#if SYSTIMER_WARNING + warn_report("[SYSTIMER] Unsupported write to registers %08lx (%08lx)\n", addr, value); +#endif + break; + } + +#if SYSTIMER_DEBUG + info_report("[SYSTIMER] Writing to %08lx = %08lx\n", addr, value); +#endif +} + + +static const MemoryRegionOps esp32c3_systimer_ops = { + .read = esp32c3_systimer_read, + .write = esp32c3_systimer_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32c3_systimer_cb(void* opaque) +{ + ESP32C3SysTimerComp* comparator = (ESP32C3SysTimerComp*) opaque; + esp32c3_systimer_notify(comparator); +} + + +static void esp32c3_systimer_reset(DeviceState* ts) +{ + ESP32C3SysTimerState *s = ESP32C3_SYSTIMER(ts); + s->conf = 0; + for (int i = 0; i < ESP32C3_SYSTIMER_COMP_COUNT; i++) { + ESP32C3SysTimerComp* comp = &s->comparators[i]; + QEMUTimer qtimer = comp->qtimer; + qemu_irq irq = comp->irq; + + /* Disable all the timers/irq first */ + timer_del(&comp->qtimer); + qemu_irq_lower(comp->irq); + + /* Reset the data of the comparator */ + memset(comp, 0, sizeof(ESP32C3SysTimerComp)); + + /* Restore the former fields that were already initialized */ + comp->qtimer = qtimer; + comp->irq = irq; + comp->systimer = s; + } +} + + +static void esp32c3_systimer_realize(DeviceState *dev, Error **errp) +{ +} + + +static void esp32c3_systimer_init(Object *obj) +{ + ESP32C3SysTimerState *s = ESP32C3_SYSTIMER(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32c3_systimer_ops, s, + TYPE_ESP32C3_SYSTIMER, ESP32C3_SYSTIMER_IO_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + + for (uint64_t i = 0; i < ESP32C3_SYSTIMER_COMP_COUNT; i++) { + s->comparators[i].systimer = s; + sysbus_init_irq(sbd, &s->comparators[i].irq); + timer_init_ns(&s->comparators[i].qtimer, QEMU_CLOCK_VIRTUAL, esp32c3_systimer_cb, &s->comparators[i]); + } +} + + +static void esp32c3_systimer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32c3_systimer_reset; + dc->realize = esp32c3_systimer_realize; +} + + +static const TypeInfo esp32c3_systimer_info = { + .name = TYPE_ESP32C3_SYSTIMER, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32C3SysTimerState), + .instance_init = esp32c3_systimer_init, + .class_init = esp32c3_systimer_class_init +}; + + +static void esp32c3_systimer_register_types(void) +{ + type_register_static(&esp32c3_systimer_info); +} + + +type_init(esp32c3_systimer_register_types) diff --git a/hw/timer/esp32c3_timg.c b/hw/timer/esp32c3_timg.c new file mode 100644 index 000000000000..a7f684a5f5c3 --- /dev/null +++ b/hw/timer/esp32c3_timg.c @@ -0,0 +1,740 @@ +/* + * ESP32-C3 "Timer Group" peripheral + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "qapi/visitor.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/registerfields.h" +#include "hw/boards.h" +#include "hw/timer/esp32c3_timg.h" + +#define TIMG_DEBUG 0 +#define TIMG_WARNING 0 + +#define FIELD_CHANGED(value1, value2, reg, field) \ + ((value1) & R_ ## reg ## _ ## field ## _MASK) != ((value2) & R_ ## reg ## _ ## field ## _MASK) + +/** + * Helper to load a 32-bit low value and a 22-bit high value into a 64-bit value + */ +static inline uint64_t load_low(uint64_t reg, uint32_t low) +{ + return (reg & (0xffffffff00000000)) | (low & UINT32_MAX); +} + +static inline uint64_t load_high(uint64_t reg, uint32_t high) +{ + return (reg & UINT32_MAX) | ((uint64_t) (high & 0x3fffff) << 32); +} + + +/** + * @brief Update the value of a counter according the QEMU virtual timer. + */ +static int64_t esp32c3_virtual_counter_update(ESP32C3VirtualCounter *counter) +{ + const int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + const int64_t elapsed_ns = now - counter->base; + const int64_t ticks = (elapsed_ns * (counter->frequency / 1000)) / 1000000; + counter->value += ticks; + counter->base = now; + return counter->value; +} + +static inline QEMUTimer* esp32c3_virtual_counter_get_timer(ESP32C3VirtualCounter *counter) +{ + return &counter->timer; +} + +static void esp32c3_virtual_counter_alarm_in_ticks(ESP32C3VirtualCounter *counter, int64_t ticks) +{ + int64_t delay_ns = (ticks * (1000000000UL / counter->frequency)); + const int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + /* This function will reschedule the clock if it was already scheduled */ + counter->base = now; + counter->value = 0; + timer_mod_ns(&counter->timer, now + delay_ns); +} + +/** + * Update the time base of the timer without updating the counter value. + * This shall be used when the counter has just been re-enabled, and the elapsed time since it was disabled + * must not be taken into account. + */ +static void esp32c3_virtual_counter_reenabled(ESP32C3VirtualCounter *counter) +{ + counter->base = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +} + +static void esp32c3_virtual_counter_reset(ESP32C3VirtualCounter* counter) +{ + timer_del(&counter->timer); + counter->base = 0; + counter->value = 0; +} + + +/** + * @brief Function called when an update of the RTC Calibration register is requested + * Perform the required calibration simulation here and update the register. + */ +static void esp32c3_timg_rtc_cali_update(ESP32C3TimgState *s, uint32_t value) +{ + const uint32_t osc_freq_arr[] = { + [ESP32C3_TIMG_CALI_RC_SLOW_CLK] = ESP32C3_RC_SLOW_FREQ, + [ESP32C3_TIMG_CALI_RC_FAST_DIV_CLK] = ESP32C3_RC_FAST_DIV_FREQ, + [ESP32C3_TIMG_CALI_XTAL32K_CLK] = ESP32C3_XTAL32K_FREQ + }; + /* Copy the new value to the register but keep RDY bit to 0 (read-only) */ + value &= ~(R_TIMG_RTCCALICFG_RDY_MASK); + + /* Check if a start (one-time or periodic) was triggered */ + if (value & (R_TIMG_RTCCALICFG_START_MASK | R_TIMG_RTCCALICFG_START_CYCLING_MASK)) { + + /* Get the clock that is being calibrated */ + const uint32_t clk = FIELD_EX32(value, TIMG_RTCCALICFG, CLK_SEL); + const uint32_t freq = osc_freq_arr[clk]; + + /* And the counter that should be reached by this clock */ + const uint32_t max_count = FIELD_EX32(value, TIMG_RTCCALICFG, MAX); + + /* Calculate how many clock cycle it would require to the XTAL_CLK to reach this count */ + const uint32_t xtal_count = (ESP32C3_XTAL_CLK * max_count) / freq; + + /* Save this count in the RTC Calibration register 1 */ + s->rtc.rtc_cali_cfg_result = xtal_count << R_TIMG_RTCCALICFG1_VALUE_SHIFT; + + value |= R_TIMG_RTCCALICFG_RDY_MASK; + + /* Clear the timeout register */ + s->rtc.rtc_cali_cfg_timeout &= ~(R_TIMG_RTCCALICFG2_TIMEOUT_MASK); + } + + s->rtc.rtc_cali_cfg = value; +} + +/** + * @brief Function called when an update on the timeout register occur. + */ +static void esp32c3_timg_rtc_cali_check_timeout(ESP32C3TimgState *s, uint32_t value) +{ + /* Let's simplify the process of timeout generation, if the timeout reset count is smaller + * than the max cali count divided by a constant, generate a timeout */ + const uint32_t count = FIELD_EX32(s->rtc.rtc_cali_cfg, TIMG_RTCCALICFG, MAX); + const uint32_t rst_cnt = FIELD_EX32(value, TIMG_RTCCALICFG2, TIMEOUT_RST_CNT); + + s->rtc.rtc_cali_cfg_timeout = value & ~(R_TIMG_RTCCALICFG2_TIMEOUT_MASK); + + if (rst_cnt == 0 || (rst_cnt < count / 10)) + { + s->rtc.rtc_cali_cfg_timeout |= R_TIMG_RTCCALICFG2_TIMEOUT_MASK; + } +} + +/** + * Functions related to Watchdog + */ + +static inline uint64_t esp32c3_wdt_ext_clk_frequency(ESP32C3WdtState* wdt) +{ + return FIELD_EX32(wdt->config0, TIMG_WDTCONFIG0, USE_XTAL) ? ESP32C3_XTAL_CLK : ESP32C3_APB_CLK; +} + +static inline bool esp32c3_wdt_is_writable(ESP32C3WdtState* wdt) +{ + return wdt->wkey == ESP32C3_WDT_DEFAULT_WKEY; +} + +static inline bool esp32c3_wdt_enabled(ESP32C3WdtState* wdt) +{ + return FIELD_EX32(wdt->config0, TIMG_T0CONFIG, EN) ? 1 : 0; +} + + +static void esp32c3_wdt_cb(void* opaque) +{ + ESP32C3WdtState* wdt = (ESP32C3WdtState*) opaque; + ESP32C3WdtStageConf conf = wdt->stage_conf[wdt->current_stage]; + + /* Check which action must be taken for the current stage */ + if (conf == ESP32C3_WDT_INTERRUPT) { + wdt->raw_st = 1; + if (wdt->int_enabled) { + qemu_irq_raise(wdt->interrupt_irq); + } + } else if (conf == ESP32C3_WDT_RESET_CPU || conf == ESP32C3_WDT_RESET_SYS) { + qemu_irq_raise(wdt->reset_irq); + /* Do not schedule anything if we have to reset the machine */ + return; + } + + const int new_stage = (wdt->current_stage + 1) % ESP32C3_WDT_STAGE_COUNT; + wdt->current_stage = new_stage; + esp32c3_virtual_counter_alarm_in_ticks(&wdt->counter, wdt->stage[new_stage]); +} + +static void esp32c3_wdt_update_prescaler(ESP32C3WdtState* wdt, uint32_t value) +{ + if (FIELD_EX32(value, TIMG_WDTCONFIG1, DIVCNT_RST) || value == 0) { + /* Avoid any divide-by-0 error in the code below */ + wdt->prescaler = 1; + } else { + wdt->prescaler = FIELD_EX32(value, TIMG_WDTCONFIG1, CLK_PRESCALE); + } + + /* Recalculate the frequency out of the new prescaler and current clock */ + wdt->counter.frequency = esp32c3_wdt_ext_clk_frequency(wdt) / wdt->prescaler; + + /* In theory we should reschedule the timer if it is currently running. + * In practice, let's say that this behavior is invalid and do not reschedule it. */ +} + +static void esp32c3_wdt_update_stage(ESP32C3WdtState* wdt, int index, uint32_t value, bool verify) +{ + wdt->stage[index] = value; + + /* If the updated stage is the current one and the watchdog is enabled, reprogram the timer */ + if (esp32c3_wdt_enabled(wdt) && wdt->current_stage == index && verify) { + /* Update the counter of the running timer, so that we can adjust the alarm */ + int64_t counter_value = esp32c3_virtual_counter_update(&wdt->counter); + int64_t diff = (int64_t) value - counter_value; + if (diff <= 0) { + /* If the difference is negative, the new limit is smaller than the current value, + * manually trigger the alarm. */ + esp32c3_wdt_cb(wdt); + } else { + /* The new alarm is set to happen in `diff` ticks, reschedule the alarm */ + esp32c3_virtual_counter_alarm_in_ticks(&wdt->counter, diff); + } + } +} + +static void esp32c3_wdt_feed(ESP32C3WdtState* wdt) +{ + if (esp32c3_wdt_enabled(wdt)) { + wdt->current_stage = 0; + esp32c3_virtual_counter_alarm_in_ticks(&wdt->counter, wdt->stage[0]); + } +} + +static void esp32c3_wdt_update_config(ESP32C3WdtState* wdt, uint32_t value) +{ + /* If the WDT is protected return */ + if (!esp32c3_wdt_is_writable(wdt)) { + return; + } + + const uint32_t former_conf = wdt->config0; + /* Clean the reserved bits */ + wdt->config0 = value & ~(R_TIMG_WDTCONFIG0_CONF_UPDATE_EN_MASK | 0x7ff); + + const bool enabled = FIELD_EX32(value, TIMG_WDTCONFIG0, EN) ? true : false; + const bool enabled_changed = FIELD_EX32(former_conf, TIMG_WDTCONFIG0, EN) != enabled; + + if (FIELD_EX32(value, TIMG_WDTCONFIG0, CONF_UPDATE_EN)) { + /* If the prescaler value or the source clock changed update the timer */ + if ((FIELD_EX32(wdt->prescaler_mirror, TIMG_WDTCONFIG1, CLK_PRESCALE) != wdt->prescaler) || + (FIELD_EX32(former_conf, TIMG_WDTCONFIG0, USE_XTAL) != FIELD_EX32(value, TIMG_WDTCONFIG0, USE_XTAL))) + { + esp32c3_wdt_update_prescaler(wdt, wdt->prescaler_mirror); + } + + /* Update the stage configuration mirror */ + wdt->stage_conf[0] = FIELD_EX32(value, TIMG_WDTCONFIG0, STG0); + wdt->stage_conf[1] = FIELD_EX32(value, TIMG_WDTCONFIG0, STG1); + wdt->stage_conf[2] = FIELD_EX32(value, TIMG_WDTCONFIG0, STG2); + wdt->stage_conf[3] = FIELD_EX32(value, TIMG_WDTCONFIG0, STG3); + + /* Update the stage values */ + for (int i = 0; i < ESP32C3_WDT_STAGE_COUNT; i++) { + /* Only reprogram the timer if the enable flag didn't change */ + esp32c3_wdt_update_stage(wdt, i, wdt->stage_mirror[i], enabled && !enabled_changed); + } + } + + /* Check if the enabled bit changed */ + if (enabled_changed) { + if (enabled) { + wdt->config0 |= R_TIMG_WDTCONFIG0_EN_MASK; + /* Timer has just been (re-)enabled, schedule the timer */ + esp32c3_virtual_counter_alarm_in_ticks(&wdt->counter, wdt->stage[0]); + } else { + wdt->config0 &= ~R_TIMG_WDTCONFIG0_EN_MASK; + /* Disable the timer! */ + timer_del(&wdt->counter.timer); + } + } +} + +/** + * Functions related to T0 timer registers + */ +static void esp32c3_t0_update_counter(ESP32C3T0State* t) +{ + int64_t previous = t->counter.value; + int64_t current = esp32c3_virtual_counter_update(&t->counter); + int64_t delta = current - previous; + const bool increase = FIELD_EX32(t->config, TIMG_T0CONFIG, INCREASE) ? true : false; + if (increase) { + t->value_rel = (t->value_rel + delta) & ESP32C3_TIMG_T0_MAX_VALUE; + } else { + t->value_rel = (t->value_rel - delta) & ESP32C3_TIMG_T0_MAX_VALUE; + } +} + + +static void esp32c3_t0_cb(void* opaque) +{ + ESP32C3T0State* t = (ESP32C3T0State*) opaque; + + /* Update the value of the counter and disable the alarm timer */ + esp32c3_virtual_counter_reset(&t->counter); + esp32c3_virtual_counter_reenabled(&t->counter); + + /* In practice, the counter is bigger than the requested value, this is due to the fact + * that there is a cost of emulation and the (Linux) kernel timer may also be busy + * doing something else before scheduling the VM. Adjust the counter to the alarm value. */ + t->value_rel = t->alarm; + + /* If the counter is set to auto-reload, set its new value */ + if (FIELD_EX32(t->config, TIMG_T0CONFIG, AUTORELOAD)) { + t->value_rel = t->value_toload; + } + + /* Alarm was triggered, clear alarm bit, set the IRQ if interrupts enabled */ + t->config &= ~R_TIMG_T0CONFIG_ALARM_EN_MASK; + t->raw_st = true; + if (t->int_enabled) { + qemu_irq_raise(t->interrupt_irq); + } +} + + +static void esp32c3_t0_counter_flush(ESP32C3T0State* t) +{ + if (FIELD_EX32(t->config, TIMG_T0CONFIG, EN)) { + esp32c3_t0_update_counter(t); + } + + t->value_flushed = t->value_rel; +} + + +static void esp32c3_t0_alarm_update(ESP32C3T0State* t) +{ + + if (FIELD_EX32(t->config, TIMG_T0CONFIG, EN) && + FIELD_EX32(t->config, TIMG_T0CONFIG, ALARM_EN)) { + + const bool increase = FIELD_EX32(t->config, TIMG_T0CONFIG, INCREASE) ? true : false; + const bool decrease = !increase; + const uint64_t alarm = t->alarm; + + /* Update the current value of the relative counter */ + esp32c3_t0_update_counter(t); + + /* No matter if we increase or decrease the counter the time difference is the same */ + const uint64_t value = t->value_rel; + uint64_t diff = llabs(alarm - value); + const uint64_t limit = ESP32C3_TIMG_T0_LIMIT; + + /* Declare all the possible scenarios as explained in the TRM */ + const bool scenario1 = alarm > value && diff > limit; + const bool scenario2 = alarm > value && diff <= limit; + const bool scenario3 = value >= alarm && diff < limit; + const bool scenario4 = value >= alarm && diff >= limit; + const bool scenario5 = alarm < value && diff > limit; + const bool scenario6 = alarm < value && diff <= limit; + const bool scenario7 = value <= alarm && diff < limit; + const bool scenario8 = value <= alarm && diff >= limit; + + if ((increase && (scenario1 || scenario3)) || (decrease && (scenario5 || scenario7))) { + /* The alarm was programmed too late, trigger an interrupt manually */ + esp32c3_t0_cb(t); + } else if ((increase && scenario2) || (decrease && scenario6)) { + /* The alarm is in range and in the future, program its trigger */ + esp32c3_virtual_counter_alarm_in_ticks(&t->counter, diff); + } else { + assert(scenario4 || scenario8); + /* The alarm is in range, in the future, but requires the timer to overflow/underflow */ + const uint64_t high = MAX(alarm, value); + const uint64_t low = MIN(alarm, value); + /* Calculate the new (tick) difference between them */ + diff = (ESP32C3_TIMG_T0_MAX_VALUE + 1 - high) + low; + esp32c3_virtual_counter_alarm_in_ticks(&t->counter, diff); + } + + } +} + + +static void esp32c3_t0_counter_load(ESP32C3T0State* t) +{ + /* Update the counter so that the (time) base is up to date */ + esp32c3_t0_update_counter(t); + + /* Set the new counter */ + t->value_rel = t->value_toload; + + /* Reprogram the alarm if necessary */ + esp32c3_t0_alarm_update(t); +} + +static void esp32c3_t0_config_update(ESP32C3T0State* t0, uint32_t value) +{ + const uint32_t former_conf = t0->config; + /* Assign the new configuration while removing the write-only bits */ + t0->config = value & ~(R_TIMG_T0CONFIG_DIVCNT_RST_MASK); + + /* If the counter was enabled until now, update its value */ + if (former_conf & R_TIMG_T0CONFIG_EN_MASK) { + esp32c3_t0_update_counter(t0); + } + + /* Calculate the new frequency */ + const uint32_t new_divider = FIELD_EX32(value, TIMG_T0CONFIG, DIVIDER); + const uint64_t new_clk = FIELD_EX32(value, TIMG_T0CONFIG, USE_XTAL) ? ESP32C3_XTAL_CLK : ESP32C3_APB_CLK; + const uint64_t new_freq = new_clk / new_divider; + if (new_freq != t0->counter.frequency) { + t0->counter.frequency = new_freq; + } + + if (value & R_TIMG_T0CONFIG_DIVCNT_RST_MASK) { + esp32c3_virtual_counter_reset(&t0->counter); + esp32c3_t0_alarm_update(t0); + } + + /* If the alarm state just changed, we have to load it or disable it */ + if (FIELD_CHANGED(former_conf, value, TIMG_T0CONFIG, ALARM_EN)) { + if (value & R_TIMG_T0CONFIG_ALARM_EN_MASK) { + esp32c3_t0_alarm_update(t0); + } else { + timer_del(&t0->counter.timer); + } + } + + /* If the direction of the counter changed, reprogram the alarm. The function esp32c3_t0_alarm_update + * will check if the counter and alarm are enabled first, no need to do it here. */ + if (FIELD_CHANGED(former_conf, value, TIMG_T0CONFIG, INCREASE)) { + esp32c3_t0_alarm_update(t0); + } + + /* Finally, check if the counter state changed */ + if (FIELD_CHANGED(former_conf, value, TIMG_T0CONFIG, EN)) { + if (value & R_TIMG_T0CONFIG_EN_MASK) { + /* the counter was disabled, it has just been re-enabled, its value should not be updated, + * but the base time should be updated to now. */ + esp32c3_virtual_counter_reenabled(&t0->counter); + esp32c3_t0_alarm_update(t0); + } else { + /* In theory, we should update the counter before disabling its timer, but in practice, we + * already did that at the beginning of this function. Thus, the base time is correct. */ + timer_del(&t0->counter.timer); + } + } +} + + +/** + * Functions related to the hardware registers + */ +static uint64_t esp32c3_timg_read(void *opaque, hwaddr addr, unsigned int size) +{ + ESP32C3TimgState *s = ESP32C3_TIMG(opaque); + + uint64_t r = 0; + switch (addr) { + case A_TIMG_RTCCALICFG: + r = s->rtc.rtc_cali_cfg; + break; + case A_TIMG_RTCCALICFG1: + r = s->rtc.rtc_cali_cfg_result; + break; + case A_TIMG_RTCCALICFG2: + r = s->rtc.rtc_cali_cfg_timeout; + break; + + + /* Timer (T0) related registers */ + case A_TIMG_T0CONFIG: + r = s->t0.config; + break; + case A_TIMG_T0LO: + r = s->t0.value_flushed & UINT32_MAX; + break; + case A_TIMG_T0HI: + r = s->t0.value_flushed >> 32; + break; + case A_TIMG_T0UPDATE: + /* Write-only register */ + break; + case A_TIMG_T0ALARMLO: + r = s->t0.alarm & UINT32_MAX; + break; + case A_TIMG_T0ALARMHI: + r = s->t0.alarm >> 32; + break; + case A_TIMG_T0LOADLO: + r = s->t0.value_toload & UINT32_MAX; + break; + case A_TIMG_T0LOADHI: + r = s->t0.value_toload >> 32; + break; + case A_TIMG_T0LOAD: + /* Write-only register */ + break; + + + /* Watchdog related registers */ + case A_TIMG_WDTCONFIG0: + r = s->wdt.config0; + break; + case A_TIMG_WDTCONFIG1: + r = s->wdt.prescaler_mirror & ~R_TIMG_WDTCONFIG1_DIVCNT_RST_MASK; + break; + case A_TIMG_WDTCONFIG2: + case A_TIMG_WDTCONFIG3: + case A_TIMG_WDTCONFIG4: + case A_TIMG_WDTCONFIG5: + r = s->wdt.stage_mirror[(addr - A_TIMG_WDTCONFIG2) / sizeof(uint32_t)]; + break; + case A_TIMG_WDTFEED: + /* This register is read-only, but avoid a warning */ + break; + case A_TIMG_WDTWPROTECT: + r = s->wdt.wkey; + break; + + case A_TIMG_INT_ENA_TIMG: + r |= s->wdt.int_enabled << R_TIMG_INT_ENA_TIMG_WDT_ENA_SHIFT; + r |= s->t0.int_enabled << R_TIMG_INT_ENA_TIMG_T0_ENA_SHIFT; + break; + case A_TIMG_INT_RAW_TIMG: + r |= s->wdt.raw_st << R_TIMG_INT_RAW_TIMG_WDT_RAW_SHIFT; + r |= s->t0.raw_st << R_TIMG_INT_RAW_TIMG_T0_RAW_SHIFT; + break; + case A_TIMG_INT_ST_TIMG: + r |= (s->wdt.int_enabled && s->wdt.raw_st) << R_TIMG_INT_ST_TIMG_WDT_ST_SHIFT; + r |= (s->t0.int_enabled && s->t0.raw_st) << R_TIMG_INT_ST_TIMG_T0_ST_SHIFT; + break; + + default: +#if TIMG_WARNING + warn_report("[TIMG] Unsupported read from %08lx\n", addr); +#endif + break; + } + +#if TIMG_DEBUG + info_report("[TIMG] Reading from %08lx (%08lx)\n", addr, r); +#endif + return r; +} + +static void esp32c3_timg_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + ESP32C3TimgState *s = ESP32C3_TIMG(opaque); + + switch(addr) { + case A_TIMG_RTCCALICFG: + esp32c3_timg_rtc_cali_update(s, value); + break; + case A_TIMG_RTCCALICFG2: + esp32c3_timg_rtc_cali_check_timeout(s, value); + break; + + /* Timer (T0) related registers */ + case A_TIMG_T0CONFIG: + esp32c3_t0_config_update(&s->t0, value); + break; + case A_TIMG_T0LO: + case A_TIMG_T0HI: + /* These registers are read-only but implement them to avoid getting a warning */ + break; + case A_TIMG_T0UPDATE: + esp32c3_t0_counter_flush(&s->t0); + break; + case A_TIMG_T0ALARMLO: + s->t0.alarm = load_low(s->t0.alarm, value); + esp32c3_t0_alarm_update(&s->t0); + break; + case A_TIMG_T0ALARMHI: + s->t0.alarm = load_high(s->t0.alarm, value); + esp32c3_t0_alarm_update(&s->t0); + break; + case A_TIMG_T0LOADLO: + s->t0.value_toload = load_low(s->t0.value_toload, value); + break; + case A_TIMG_T0LOADHI: + s->t0.value_toload = load_high(s->t0.value_toload, value); + break; + case A_TIMG_T0LOAD: + esp32c3_t0_counter_load(&s->t0); + break; + + + /* Watchdog related registers */ + case A_TIMG_WDTCONFIG0: + esp32c3_wdt_update_config(&s->wdt, value); + break; + case A_TIMG_WDTCONFIG1: + s->wdt.prescaler_mirror = value; + break; + case A_TIMG_WDTCONFIG2: + case A_TIMG_WDTCONFIG3: + case A_TIMG_WDTCONFIG4: + case A_TIMG_WDTCONFIG5: + s->wdt.stage_mirror[(addr - A_TIMG_WDTCONFIG2) / sizeof(uint32_t)] = value; + break; + case A_TIMG_WDTFEED: + esp32c3_wdt_feed(&s->wdt); + break; + case A_TIMG_WDTWPROTECT: + s->wdt.wkey = value; + break; + + /* Interrupt related registers */ + case A_TIMG_INT_ENA_TIMG: + s->wdt.int_enabled = FIELD_EX32(value, TIMG_INT_ENA_TIMG, WDT_ENA) ? true : false; + s->t0.int_enabled = FIELD_EX32(value, TIMG_INT_ENA_TIMG, T0_ENA) ? true : false; + break; + case A_TIMG_INT_CLR_TIMG: + if (FIELD_EX32(value, TIMG_INT_CLR_TIMG, WDT_CLR)) { + s->wdt.raw_st = 0; + qemu_irq_lower(s->wdt.interrupt_irq); + } + if (FIELD_EX32(value, TIMG_INT_CLR_TIMG, T0_CLR)) { + s->t0.raw_st = 0; + qemu_irq_lower(s->t0.interrupt_irq); + } + break; + case A_TIMG_INT_RAW_TIMG: + case A_TIMG_INT_ST_TIMG: + break; + + default: +#if TIMG_WARNING + warn_report("[TIMG] Unsupported write to %08lx (%08lx)\n", addr, value); +#endif + break; + } + +#if TIMG_DEBUG + info_report("[TIMG] Writing to %08lx = %08lx\n", addr, value); +#endif +} + + +static const MemoryRegionOps esp32c3_timg_ops = { + .read = esp32c3_timg_read, + .write = esp32c3_timg_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + + +static void esp32c3_timg_reset(DeviceState* ts) +{ + ESP32C3TimgState *s = ESP32C3_TIMG(ts); + + /* Reset watchdog */ + esp32c3_virtual_counter_reset(&s->wdt.counter); + s->wdt.config0 = 0; + s->wdt.wkey = ESP32C3_WDT_DEFAULT_WKEY; + s->wdt.current_stage = 0; + memset(&s->wdt.stage_conf, 0, sizeof(s->wdt.stage_conf)); + s->wdt.stage[0] = 0x26000000; + s->wdt.stage[1] = 0x7FFFFFFF; + s->wdt.stage[2] = 0x0FFFFFFF; + s->wdt.stage[3] = 0x0FFFFFFF; + s->wdt.prescaler = 0x100; + s->wdt.raw_st = 0; + s->wdt.int_enabled = 0; + + /* Reset Timer0 */ + esp32c3_virtual_counter_reset(&s->t0.counter); + s->t0.raw_st = 0; + s->t0.int_enabled = 0; + s->t0.value_rel = 0; + /* Set teh divider to 1 */ + s->t0.config = 1 << R_TIMG_T0CONFIG_DIVIDER_SHIFT; +} + + +static void esp32c3_timg_realize(DeviceState *dev, Error **errp) +{ +} + + +static void esp32c3_timg_init(Object *obj) +{ + ESP32C3TimgState *s = ESP32C3_TIMG(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32c3_timg_ops, s, + TYPE_ESP32C3_TIMG, ESP32C3_TIMG_IO_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + + /* Set default value to calibration register */ + s->rtc.rtc_cali_cfg = 1 << R_TIMG_RTCCALICFG_MAX_SHIFT | + 1 << R_TIMG_RTCCALICFG_CLK_SEL_SHIFT | + 1 << R_TIMG_RTCCALICFG_START_CYCLING_SHIFT; + + /* Watchdog initialization */ + s->wdt.wkey = ESP32C3_WDT_DEFAULT_WKEY; + qdev_init_gpio_out_named(DEVICE(sbd), &s->wdt.reset_irq, ESP32C3_WDT_IRQ_RESET, 1); + qdev_init_gpio_out_named(DEVICE(sbd), &s->wdt.interrupt_irq, ESP32C3_WDT_IRQ_INTERRUPT, 1); + timer_init_ns(esp32c3_virtual_counter_get_timer(&s->wdt.counter), QEMU_CLOCK_VIRTUAL, esp32c3_wdt_cb, &s->wdt); + s->wdt.stage[0] = 0x26000000; + s->wdt.stage[1] = 0x7FFFFFFF; + s->wdt.stage[2] = 0x0FFFFFFF; + s->wdt.stage[3] = 0x0FFFFFFF; + s->wdt.prescaler = 0x100; + + + /* Timer T0 initialization */ + s->t0.config = 1 << R_TIMG_T0CONFIG_DIVIDER_SHIFT; + qdev_init_gpio_out_named(DEVICE(sbd), &s->t0.interrupt_irq, ESP32C3_T0_IRQ_INTERRUPT, 1); + timer_init_ns(esp32c3_virtual_counter_get_timer(&s->t0.counter), QEMU_CLOCK_VIRTUAL, esp32c3_t0_cb, &s->t0); +} + +static Property esp32c3_timg_properties[] = { + // DEFINE_PROP_BOOL("wdt_disable", ESP32C3TimgState, wdt_disable, false), + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32c3_timg_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32c3_timg_reset; + dc->realize = esp32c3_timg_realize; + device_class_set_props(dc, esp32c3_timg_properties); +} + +static const TypeInfo esp32c3_timg_info = { + .name = TYPE_ESP32C3_TIMG, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32C3TimgState), + .instance_init = esp32c3_timg_init, + .class_init = esp32c3_timg_class_init +}; + +static void esp32c3_timg_register_types(void) +{ + type_register_static(&esp32c3_timg_info); +} + +type_init(esp32c3_timg_register_types) diff --git a/hw/timer/meson.build b/hw/timer/meson.build index 03092e2cebf4..e148cd1219a2 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -34,6 +34,8 @@ softmmu_ss.add(when: 'CONFIG_SSE_TIMER', if_true: files('sse-timer.c')) softmmu_ss.add(when: 'CONFIG_STELLARIS_GPTM', if_true: files('stellaris-gptm.c')) softmmu_ss.add(when: 'CONFIG_STM32F2XX_TIMER', if_true: files('stm32f2xx_timer.c')) softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_timer.c')) +softmmu_ss.add(when: 'CONFIG_XTENSA_ESP32', if_true: files('esp32_frc_timer.c', 'esp32_timg.c')) +softmmu_ss.add(when: 'CONFIG_RISCV_ESP32C3', if_true: files('esp32c3_timg.c', 'esp32c3_systimer.c')) specific_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_timer.c')) softmmu_ss.add(when: 'CONFIG_SIFIVE_PWM', if_true: files('sifive_pwm.c')) diff --git a/hw/timer/trace-events b/hw/timer/trace-events index 3eccef83858f..4f5bb70fba39 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -77,6 +77,14 @@ avr_timer16_interrupt_overflow(const char *reason) "overflow: %s" avr_timer16_next_alarm(uint64_t delay_ns) "next alarm: %" PRIu64 " ns from now" avr_timer16_clksrc_update(uint64_t freq_hz, uint64_t period_ns, uint64_t delay_s) "timer frequency: %" PRIu64 " Hz, period: %" PRIu64 " ns (%" PRId64 " us)" + +# esp32_frc_timer.c +esp32_frc_timer_read(uint64_t addr, uint32_t value) "read addr 0x%" PRIx64 " data 0x%" PRIx32 +esp32_frc_timer_write(uint64_t addr, uint32_t value) "write addr 0x%" PRIx64 " data 0x%" PRIx32 +esp32_frc_timer_update_config(uint64_t ns_now, uint32_t count_now, int enable, int level_int, int autoload, uint32_t prescaler) "update now: %" PRIu64 " count: 0x%" PRIx32 " enable: %d level_int: %d autoload: %d prescaler: %" PRIu32 +esp32_frc_timer_cb(uint64_t ns_now, uint32_t count_now) "alarm now: %" PRIu64 " count: 0x%" PRIx32 +esp32_frc_timer_update_alarm(uint64_t ns_now, uint32_t count_now, uint64_t ticks, uint64_t ns_to_alarm) "set alarm now: %" PRIu64 " count: 0x%" PRIx32 " ticks: %" PRIu64 " ns_to_alarm: %" PRIu64 + # sse_counter.c sse_counter_control_read(uint64_t offset, uint64_t data, unsigned size) "SSE system counter control frame read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" sse_counter_control_write(uint64_t offset, uint64_t data, unsigned size) "SSE system counter control framen write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" diff --git a/hw/xtensa/Kconfig b/hw/xtensa/Kconfig index 0740657ea58f..6a09c5b7fc16 100644 --- a/hw/xtensa/Kconfig +++ b/hw/xtensa/Kconfig @@ -12,3 +12,15 @@ config XTENSA_XTFPGA select OPENCORES_ETH select PFLASH_CFI01 select SERIAL + +config XTENSA_ESP32 + bool + select SSI + select SSI_M25P80 + select UNIMP + select OPENCORES_ETH + select DWC_SDMMC + select TMP105 + select LED + + diff --git a/hw/xtensa/esp32.c b/hw/xtensa/esp32.c new file mode 100644 index 000000000000..8bd4a41b33c9 --- /dev/null +++ b/hw/xtensa/esp32.c @@ -0,0 +1,978 @@ +/* + * ESP32 SoC and machine + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qemu/units.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/sysbus.h" +#include "hw/i2c/esp32_i2c.h" +#include "hw/xtensa/xtensa_memory.h" +#include "hw/misc/unimp.h" +#include "hw/misc/unimp-default.h" +#include "hw/irq.h" +#include "hw/i2c/i2c.h" +#include "hw/qdev-properties.h" +#include "hw/xtensa/esp32.h" +#include "hw/misc/ssi_psram.h" +#include "hw/sd/dwc_sdmmc.h" +#include "core-esp32/core-isa.h" +#include "qemu/datadir.h" +#include "sysemu/sysemu.h" +#include "sysemu/reset.h" +#include "sysemu/cpus.h" +#include "sysemu/runstate.h" +#include "sysemu/blockdev.h" +#include "sysemu/block-backend.h" +#include "exec/exec-all.h" +#include "net/net.h" +#include "elf.h" + +#define TYPE_ESP32_SOC "xtensa.esp32" +#define ESP32_SOC(obj) OBJECT_CHECK(Esp32SocState, (obj), TYPE_ESP32_SOC) + +#define TYPE_ESP32_CPU XTENSA_CPU_TYPE_NAME("esp32") + + + +enum { + ESP32_MEMREGION_IROM, + ESP32_MEMREGION_DROM, + ESP32_MEMREGION_DRAM, + ESP32_MEMREGION_IRAM, + ESP32_MEMREGION_ICACHE0, + ESP32_MEMREGION_ICACHE1, + ESP32_MEMREGION_RTCSLOW, + ESP32_MEMREGION_RTCFAST_D, + ESP32_MEMREGION_RTCFAST_I, +}; + +static const struct MemmapEntry { + hwaddr base; + hwaddr size; +} esp32_memmap[] = { + [ESP32_MEMREGION_DROM] = { 0x3ff90000, 0x10000 }, + [ESP32_MEMREGION_IROM] = { 0x40000000, 0x70000 }, + [ESP32_MEMREGION_DRAM] = { 0x3ffae000, 0x52000 }, + [ESP32_MEMREGION_IRAM] = { 0x40080000, 0x40000 }, + [ESP32_MEMREGION_ICACHE0] = { 0x40070000, 0x8000 }, + [ESP32_MEMREGION_ICACHE1] = { 0x40078000, 0x8000 }, + [ESP32_MEMREGION_RTCSLOW] = { 0x50000000, 0x2000 }, + [ESP32_MEMREGION_RTCFAST_I] = { 0x400C0000, 0x2000 }, + [ESP32_MEMREGION_RTCFAST_D] = { 0x3ff80000, 0x2000 }, +}; + + +#define ESP32_SOC_RESET_PROCPU 0x1 +#define ESP32_SOC_RESET_APPCPU 0x2 +#define ESP32_SOC_RESET_PERIPH 0x4 +#define ESP32_SOC_RESET_DIG (ESP32_SOC_RESET_PROCPU | ESP32_SOC_RESET_APPCPU | ESP32_SOC_RESET_PERIPH) +#define ESP32_SOC_RESET_RTC 0x8 +#define ESP32_SOC_RESET_ALL (ESP32_SOC_RESET_RTC | ESP32_SOC_RESET_DIG) + + + + +static void remove_cpu_watchpoints(XtensaCPU* xcs) +{ + for (int i = 0; i < MAX_NDBREAK; ++i) { + if (xcs->env.cpu_watchpoint[i]) { + cpu_watchpoint_remove_by_ref(CPU(xcs), xcs->env.cpu_watchpoint[i]); + xcs->env.cpu_watchpoint[i] = NULL; + } + } +} + +static void esp32_dig_reset(void *opaque, int n, int level) +{ + Esp32SocState *s = ESP32_SOC(opaque); + if (level) { + esp32_dport_clear_ill_trap_state(&s->dport); + s->requested_reset = ESP32_SOC_RESET_DIG; + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + } +} + +static void esp32_cpu_reset(void* opaque, int n, int level) +{ + Esp32SocState *s = ESP32_SOC(opaque); + if (level) { + s->requested_reset = (n == 0) ? ESP32_SOC_RESET_PROCPU : ESP32_SOC_RESET_APPCPU; + /* Use different cause for APP CPU so that its reset doesn't cause QEMU to exit, + * when -no-reboot option is given. + */ + ShutdownCause cause = (n == 0) ? SHUTDOWN_CAUSE_GUEST_RESET : SHUTDOWN_CAUSE_SUBSYSTEM_RESET; + s->rtc_cntl.reset_cause[n] = ESP32_SW_CPU_RESET; + qemu_system_reset_request(cause); + } +} + +static void esp32_timg_cpu_reset(void* opaque, int n, int level) +{ + Esp32SocState *s = ESP32_SOC(opaque); + if (level) { + s->requested_reset = (n == 0) ? ESP32_SOC_RESET_PROCPU : ESP32_SOC_RESET_APPCPU; + /* Use different cause for APP CPU so that its reset doesn't cause QEMU to exit, + * when -no-reboot option is given. + */ + ShutdownCause cause = (n == 0) ? SHUTDOWN_CAUSE_GUEST_RESET : SHUTDOWN_CAUSE_SUBSYSTEM_RESET; + s->rtc_cntl.reset_cause[n] = ESP32_TGWDT_CPU_RESET; + qemu_system_reset_request(cause); + } +} + +static void esp32_timg_sys_reset(void* opaque, int n, int level) +{ + Esp32SocState *s = ESP32_SOC(opaque); + if (level) { + esp32_dport_clear_ill_trap_state(&s->dport); + s->requested_reset = ESP32_SOC_RESET_DIG; + for (int i = 0; i < ESP32_CPU_COUNT; ++i) { + s->rtc_cntl.reset_cause[i] = ESP32_TG0WDT_SYS_RESET + n; + } + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + } +} + +static void esp32_soc_reset(DeviceState *dev) +{ + Esp32SocState *s = ESP32_SOC(dev); + + uint32_t strap_mode = s->gpio.strap_mode; + + bool flash_boot_mode = ((strap_mode & 0x10) || (strap_mode & 0x1f) == 0x0c); + qemu_set_irq(qdev_get_gpio_in_named(DEVICE(&s->flash_enc), ESP32_FLASH_ENCRYPTION_DL_MODE_GPIO, 0), !flash_boot_mode); + + if (s->requested_reset == 0) { + s->requested_reset = ESP32_SOC_RESET_ALL; + } + if (s->requested_reset & ESP32_SOC_RESET_RTC) { + device_cold_reset(DEVICE(&s->rtc_cntl)); + } + if (s->requested_reset & ESP32_SOC_RESET_PERIPH) { + device_cold_reset(DEVICE(&s->dport)); + device_cold_reset(DEVICE(&s->intmatrix)); + device_cold_reset(DEVICE(&s->aes)); + device_cold_reset(DEVICE(&s->rsa)); + device_cold_reset(DEVICE(&s->gpio)); + for (int i = 0; i < ESP32_UART_COUNT; ++i) { + device_cold_reset(DEVICE(&s->uart[i])); + } + for (int i = 0; i < ESP32_FRC_COUNT; ++i) { + device_cold_reset(DEVICE(&s->frc_timer[i])); + } + for (int i = 0; i < ESP32_TIMG_COUNT; ++i) { + device_cold_reset(DEVICE(&s->timg[i])); + } + s->timg[0].flash_boot_mode = flash_boot_mode; + for (int i = 0; i < ESP32_SPI_COUNT; ++i) { + device_cold_reset(DEVICE(&s->spi[i])); + } + for (int i = 0; i < ESP32_I2C_COUNT; i++) { + device_cold_reset(DEVICE(&s->i2c[i])); + } + device_cold_reset(DEVICE(&s->efuse)); + if (s->eth) { + device_cold_reset(s->eth); + } + if (s->wifi_dev) { + device_cold_reset(s->wifi_dev); + } + } + if (s->requested_reset & ESP32_SOC_RESET_PROCPU) { + xtensa_select_static_vectors(&s->cpu[0].env, s->rtc_cntl.stat_vector_sel[0]); + remove_cpu_watchpoints(&s->cpu[0]); + cpu_reset(CPU(&s->cpu[0])); + } + if (s->requested_reset & ESP32_SOC_RESET_APPCPU) { + xtensa_select_static_vectors(&s->cpu[1].env, s->rtc_cntl.stat_vector_sel[1]); + remove_cpu_watchpoints(&s->cpu[1]); + cpu_reset(CPU(&s->cpu[1])); + } + s->requested_reset = 0; +} + +static void esp32_cpu_stall(void* opaque, int n, int level) +{ + Esp32SocState *s = ESP32_SOC(opaque); + + bool stall; + if (n == 0) { + stall = s->rtc_cntl.cpu_stall_state[0]; + } else { + stall = s->rtc_cntl.cpu_stall_state[1] || s->dport.appcpu_stall_state || (!s->dport.appcpu_clkgate_state); + } + + if (stall != s->cpu[n].env.runstall) { + xtensa_runstall(&s->cpu[n].env, stall); + } +} + +static void esp32_clk_update(void* opaque, int n, int level) +{ + Esp32SocState *s = ESP32_SOC(opaque); + if (!level) { + return; + } + + /* APB clock */ + uint32_t apb_clk_freq, cpu_clk_freq; + if (s->rtc_cntl.soc_clk == ESP32_SOC_CLK_PLL) { + const uint32_t cpu_clk_mul[] = {1, 2, 3}; + apb_clk_freq = s->rtc_cntl.pll_apb_freq; + cpu_clk_freq = cpu_clk_mul[s->dport.cpuperiod_sel] * apb_clk_freq; + } else { + apb_clk_freq = s->rtc_cntl.xtal_apb_freq; + cpu_clk_freq = apb_clk_freq; + } + qdev_prop_set_int32(DEVICE(&s->frc_timer), "apb_freq", apb_clk_freq); + qdev_prop_set_int32(DEVICE(&s->timg[0]), "apb_freq", apb_clk_freq); + qdev_prop_set_int32(DEVICE(&s->timg[1]), "apb_freq", apb_clk_freq); + clock_update_hz(s->cpu[0].clock, cpu_clk_freq ); + clock_update_hz(s->cpu[1].clock, cpu_clk_freq ); +} + +static void esp32_soc_add_periph_device(MemoryRegion *dest, void* dev, hwaddr dport_base_addr) +{ + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); + memory_region_add_subregion_overlap(dest, dport_base_addr, mr, 0); + MemoryRegion *mr_apb = g_new(MemoryRegion, 1); + char *name = g_strdup_printf("mr-apb-0x%08x", (uint32_t) dport_base_addr); + memory_region_init_alias(mr_apb, OBJECT(dev), name, mr, 0, memory_region_size(mr)); + memory_region_add_subregion_overlap(dest, dport_base_addr - DR_REG_DPORT_APB_BASE + APB_REG_BASE, mr_apb, 0); + g_free(name); +} + +static void esp32_soc_add_periph_device_prio(MemoryRegion *dest, void* dev, hwaddr dport_base_addr, int priority) +{ + MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); + memory_region_add_subregion_overlap(dest, dport_base_addr, mr, priority); + MemoryRegion *mr_apb = g_new(MemoryRegion, 1); + char *name = g_strdup_printf("mr-apb-0x%08x", (uint32_t) dport_base_addr); + memory_region_init_alias(mr_apb, OBJECT(dev), name, mr, 0, memory_region_size(mr)); + memory_region_add_subregion_overlap(dest, dport_base_addr - DR_REG_DPORT_APB_BASE + APB_REG_BASE, mr_apb, priority); + g_free(name); +} + +static void esp32_soc_add_unimp_default_device(MemoryRegion *dest, const char* name, hwaddr dport_base_addr, size_t size, uint64_t default_value) +{ + create_unimplemented_default_device(name, dport_base_addr, size, default_value); + char * name_apb = g_strdup_printf("%s-apb", name); + create_unimplemented_default_device(name_apb, dport_base_addr - DR_REG_DPORT_APB_BASE + APB_REG_BASE, size, default_value); + g_free(name_apb); +} + +static void esp32_soc_realize(DeviceState *dev, Error **errp) +{ + Esp32SocState *s = ESP32_SOC(dev); + MachineState *ms = MACHINE(qdev_get_machine()); + + const struct MemmapEntry *memmap = esp32_memmap; + MemoryRegion *sys_mem = get_system_memory(); + + MemoryRegion *dram = g_new(MemoryRegion, 1); + MemoryRegion *iram = g_new(MemoryRegion, 1); + MemoryRegion *icache0 = g_new(MemoryRegion, 1); + MemoryRegion *icache1 = g_new(MemoryRegion, 1); + MemoryRegion *rtcslow = g_new(MemoryRegion, 1); + MemoryRegion *rtcfast_i = g_new(MemoryRegion, 1); + MemoryRegion *rtcfast_d = g_new(MemoryRegion, 1); + + for (int i = 0; i < ms->smp.cpus; ++i) { + MemoryRegion *drom = g_new(MemoryRegion, 1); + MemoryRegion *irom = g_new(MemoryRegion, 1); + + char name[16]; + snprintf(name, sizeof(name), "esp32.irom.cpu%d", i); + memory_region_init_rom(irom, NULL, name, + memmap[ESP32_MEMREGION_IROM].size, &error_fatal); + memory_region_add_subregion(&s->cpu_specific_mem[i], memmap[ESP32_MEMREGION_IROM].base, irom); + + + snprintf(name, sizeof(name), "esp32.drom.cpu%d", i); + memory_region_init_alias(drom, NULL, name, irom, 0x60000, memmap[ESP32_MEMREGION_DROM].size); + memory_region_add_subregion(&s->cpu_specific_mem[i], memmap[ESP32_MEMREGION_DROM].base, drom); + } + + memory_region_init_ram(dram, NULL, "esp32.dram", + memmap[ESP32_MEMREGION_DRAM].size, &error_fatal); + memory_region_add_subregion(sys_mem, memmap[ESP32_MEMREGION_DRAM].base, dram); + + memory_region_init_ram(iram, NULL, "esp32.iram", + memmap[ESP32_MEMREGION_IRAM].size, &error_fatal); + memory_region_add_subregion(sys_mem, memmap[ESP32_MEMREGION_IRAM].base, iram); + + memory_region_init_ram(icache0, NULL, "esp32.icache0", + memmap[ESP32_MEMREGION_ICACHE0].size, &error_fatal); + memory_region_add_subregion(sys_mem, memmap[ESP32_MEMREGION_ICACHE0].base, icache0); + + memory_region_init_ram(icache1, NULL, "esp32.icache1", + memmap[ESP32_MEMREGION_ICACHE1].size, &error_fatal); + memory_region_add_subregion(sys_mem, memmap[ESP32_MEMREGION_ICACHE1].base, icache1); + + memory_region_init_ram(rtcslow, NULL, "esp32.rtcslow", + memmap[ESP32_MEMREGION_RTCSLOW].size, &error_fatal); + memory_region_add_subregion(sys_mem, memmap[ESP32_MEMREGION_RTCSLOW].base, rtcslow); + + /* RTC Fast memory is only accessible by the PRO CPU */ + + memory_region_init_ram(rtcfast_i, NULL, "esp32.rtcfast_i", + memmap[ESP32_MEMREGION_RTCSLOW].size, &error_fatal); + memory_region_add_subregion(&s->cpu_specific_mem[0], memmap[ESP32_MEMREGION_RTCFAST_I].base, rtcfast_i); + + memory_region_init_alias(rtcfast_d, NULL, "esp32.rtcfast_d", rtcfast_i, 0, memmap[ESP32_MEMREGION_RTCFAST_D].size); + memory_region_add_subregion(&s->cpu_specific_mem[0], memmap[ESP32_MEMREGION_RTCFAST_D].base, rtcfast_d); + + for (int i = 0; i < ms->smp.cpus; ++i) { + qdev_realize(DEVICE(&s->cpu[i]), NULL, &error_fatal); + } + + qdev_realize(DEVICE(&s->dport), &s->periph_bus, &error_fatal); + MemoryRegion* dport_mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dport), 0); + + memory_region_add_subregion(sys_mem, DR_REG_DPORT_BASE, dport_mem); + qdev_connect_gpio_out_named(DEVICE(&s->dport), ESP32_DPORT_APPCPU_RESET_GPIO, 0, + qdev_get_gpio_in_named(dev, ESP32_RTC_CPU_RESET_GPIO, 1)); + qdev_connect_gpio_out_named(DEVICE(&s->dport), ESP32_DPORT_APPCPU_STALL_GPIO, 0, + qdev_get_gpio_in_named(dev, ESP32_RTC_CPU_STALL_GPIO, 1)); + qdev_connect_gpio_out_named(DEVICE(&s->rtc_cntl), ESP32_DPORT_CLK_UPDATE_GPIO, 0, + qdev_get_gpio_in_named(dev, ESP32_RTC_CLK_UPDATE_GPIO, 0)); + + for (int i = 0; i < ESP32_CPU_COUNT; ++i) { + char name[16]; + snprintf(name, sizeof(name), "cpu%d", i); + object_property_set_link(OBJECT(&s->intmatrix), name, OBJECT(qemu_get_cpu(i)), &error_abort); + } + qdev_realize(DEVICE(&s->intmatrix), &s->periph_bus, &error_fatal); + DeviceState* intmatrix_dev = DEVICE(&s->intmatrix); + memory_region_add_subregion_overlap(dport_mem, ESP32_DPORT_PRO_INTMATRIX_BASE, sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->intmatrix), 0), -1); + + bool init_cache_err = false; + if (s->dport.flash_blk) { + for (int i = 0; i < ESP32_CPU_COUNT; ++i) { + Esp32CacheRegionState *drom0 = &s->dport.cache_state[i].drom0; + memory_region_add_subregion_overlap(&s->cpu_specific_mem[i], drom0->base, &drom0->illegal_access_trap_mem, -2); + memory_region_add_subregion_overlap(&s->cpu_specific_mem[i], drom0->base, &drom0->mem, -1); + Esp32CacheRegionState *iram0 = &s->dport.cache_state[i].iram0; + memory_region_add_subregion_overlap(&s->cpu_specific_mem[i], iram0->base, &iram0->illegal_access_trap_mem, -2); + memory_region_add_subregion_overlap(&s->cpu_specific_mem[i], iram0->base, &iram0->mem, -1); + } + init_cache_err = true; + } + if (s->dport.has_psram) { + for (int i = 0; i < ESP32_CPU_COUNT; ++i) { + Esp32CacheRegionState *dram1 = &s->dport.cache_state[i].dram1; + memory_region_add_subregion_overlap(&s->cpu_specific_mem[i], dram1->base, &dram1->illegal_access_trap_mem, -2); + memory_region_add_subregion_overlap(&s->cpu_specific_mem[i], dram1->base, &dram1->mem, -1); + } + init_cache_err = true; + } + if (init_cache_err) { + qdev_connect_gpio_out_named(DEVICE(&s->dport), ESP32_DPORT_CACHE_ILL_IRQ_GPIO, 0, + qdev_get_gpio_in(DEVICE(&s->intmatrix), ETS_CACHE_IA_INTR_SOURCE)); + } + + int n_crosscore_irqs = ESP32_DPORT_CROSSCORE_INT_COUNT; + object_property_set_int(OBJECT(&s->crosscore_int), "n_irqs", n_crosscore_irqs, &error_abort); + qdev_realize(DEVICE(&s->crosscore_int), &s->periph_bus, &error_fatal); + memory_region_add_subregion_overlap(dport_mem, ESP32_DPORT_CROSSCORE_INT_BASE, &s->crosscore_int.iomem, -1); + + for (int index = 0; index < ESP32_DPORT_CROSSCORE_INT_COUNT; ++index) { + qemu_irq target = qdev_get_gpio_in(DEVICE(&s->intmatrix), ETS_FROM_CPU_INTR0_SOURCE + index); + assert(target); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->crosscore_int), index, target); + } + + qdev_realize(DEVICE(&s->rsa), &s->periph_bus, &error_fatal); + esp32_soc_add_periph_device(sys_mem, &s->rsa, DR_REG_RSA_BASE); + + qdev_realize(DEVICE(&s->sha), &s->periph_bus, &error_fatal); + esp32_soc_add_periph_device(sys_mem, &s->sha, DR_REG_SHA_BASE); + + qdev_realize(DEVICE(&s->unknown), &s->periph_bus, &error_fatal); + esp32_soc_add_periph_device_prio(sys_mem, &s->unknown, 0x3ff00000, -1001); + + qdev_realize(DEVICE(&s->aes), &s->periph_bus, &error_fatal); + esp32_soc_add_periph_device(sys_mem, &s->aes, DR_REG_AES_BASE); + + qdev_realize(DEVICE(&s->ledc), &s->periph_bus, &error_fatal); + esp32_soc_add_periph_device(sys_mem, &s->ledc, DR_REG_LEDC_BASE); + + qdev_realize(DEVICE(&s->rtc_cntl), &s->rtc_bus, &error_fatal); + esp32_soc_add_periph_device(sys_mem, &s->rtc_cntl, DR_REG_RTCCNTL_BASE); + + qdev_connect_gpio_out_named(DEVICE(&s->rtc_cntl), ESP32_RTC_DIG_RESET_GPIO, 0, + qdev_get_gpio_in_named(dev, ESP32_RTC_DIG_RESET_GPIO, 0)); + qdev_connect_gpio_out_named(DEVICE(&s->rtc_cntl), ESP32_RTC_CLK_UPDATE_GPIO, 0, + qdev_get_gpio_in_named(dev, ESP32_RTC_CLK_UPDATE_GPIO, 0)); + for (int i = 0; i < ms->smp.cpus; ++i) { + qdev_connect_gpio_out_named(DEVICE(&s->rtc_cntl), ESP32_RTC_CPU_RESET_GPIO, i, + qdev_get_gpio_in_named(dev, ESP32_RTC_CPU_RESET_GPIO, i)); + qdev_connect_gpio_out_named(DEVICE(&s->rtc_cntl), ESP32_RTC_CPU_STALL_GPIO, i, + qdev_get_gpio_in_named(dev, ESP32_RTC_CPU_STALL_GPIO, i)); + } + + qdev_realize(DEVICE(&s->gpio), &s->periph_bus, &error_fatal); + esp32_soc_add_periph_device(sys_mem, &s->gpio, DR_REG_GPIO_BASE); + + for (int i = 0; i < ESP32_UART_COUNT; ++i) { + const hwaddr uart_base[] = {DR_REG_UART_BASE, DR_REG_UART1_BASE, DR_REG_UART2_BASE}; + qdev_realize(DEVICE(&s->uart[i]), &s->periph_bus, &error_fatal); + esp32_soc_add_periph_device(sys_mem, &s->uart[i], uart_base[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, + qdev_get_gpio_in(intmatrix_dev, ETS_UART0_INTR_SOURCE + i)); + } + + for (int i = 0; i < ESP32_FRC_COUNT; ++i) { + qdev_realize(DEVICE(&s->frc_timer[i]), &s->periph_bus, &error_fatal); + + esp32_soc_add_periph_device(sys_mem, &s->frc_timer[i], DR_REG_FRC_TIMER_BASE + i * ESP32_FRC_TIMER_STRIDE); + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->frc_timer[i]), 0, + qdev_get_gpio_in(intmatrix_dev, ETS_TIMER1_INTR_SOURCE + i)); + } + + for (int i = 0; i < ESP32_TIMG_COUNT; ++i) { + s->timg[i].id = i; + + const hwaddr timg_base[] = {DR_REG_TIMERGROUP0_BASE, DR_REG_TIMERGROUP1_BASE}; + qdev_realize(DEVICE(&s->timg[i]), &s->periph_bus, &error_fatal); + + esp32_soc_add_periph_device(sys_mem, &s->timg[i], timg_base[i]); + + int timg_level_int[] = { ETS_TG0_T0_LEVEL_INTR_SOURCE, ETS_TG1_T0_LEVEL_INTR_SOURCE }; + int timg_edge_int[] = { ETS_TG0_T0_EDGE_INTR_SOURCE, ETS_TG1_T0_EDGE_INTR_SOURCE }; + for (Esp32TimgInterruptType it = TIMG_T0_INT; it < TIMG_INT_MAX; ++it) { + sysbus_connect_irq(SYS_BUS_DEVICE(&s->timg[i]), it, qdev_get_gpio_in(intmatrix_dev, timg_level_int[i] + it)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->timg[i]), TIMG_INT_MAX + it, qdev_get_gpio_in(intmatrix_dev, timg_edge_int[i] + it)); + } + + qdev_connect_gpio_out_named(DEVICE(&s->timg[i]), ESP32_TIMG_WDT_CPU_RESET_GPIO, 0, + qdev_get_gpio_in_named(dev, ESP32_TIMG_WDT_CPU_RESET_GPIO, i)); + qdev_connect_gpio_out_named(DEVICE(&s->timg[i]), ESP32_TIMG_WDT_SYS_RESET_GPIO, 0, + qdev_get_gpio_in_named(dev, ESP32_TIMG_WDT_SYS_RESET_GPIO, i)); + } + s->timg[0].wdt_en_at_reset = true; + + for (int i = 0; i < ESP32_SPI_COUNT; ++i) { + const hwaddr spi_base[] = { + DR_REG_SPI0_BASE, DR_REG_SPI1_BASE, DR_REG_SPI2_BASE, DR_REG_SPI3_BASE + }; + qdev_realize(DEVICE(&s->spi[i]), &s->periph_bus, &error_fatal); + + esp32_soc_add_periph_device(sys_mem, &s->spi[i], spi_base[i]); + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0, + qdev_get_gpio_in(intmatrix_dev, ETS_SPI0_INTR_SOURCE + i)); + } + + for (int i = 0; i < ESP32_I2C_COUNT; i++) { + const hwaddr i2c_base[] = { + DR_REG_I2C_EXT_BASE, DR_REG_I2C1_EXT_BASE + }; + qdev_realize(DEVICE(&s->i2c[i]), &s->periph_bus, &error_fatal); + + esp32_soc_add_periph_device(sys_mem, &s->i2c[i], i2c_base[i]); + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0, + qdev_get_gpio_in(intmatrix_dev, ETS_I2C_EXT0_INTR_SOURCE + i)); + } + + qdev_realize(DEVICE(&s->rng), &s->periph_bus, &error_fatal); + esp32_soc_add_periph_device(sys_mem, &s->rng, ESP32_RNG_BASE); + + qdev_realize(DEVICE(&s->ana), &s->periph_bus, &error_fatal); + esp32_soc_add_periph_device(sys_mem, &s->ana, DR_REG_ANA_BASE); + + qdev_realize(DEVICE(&s->phya), &s->periph_bus, &error_fatal); + esp32_soc_add_periph_device(sys_mem, &s->phya, DR_REG_PHYA_BASE); + + qdev_realize(DEVICE(&s->fe), &s->periph_bus, &error_fatal); + esp32_soc_add_periph_device(sys_mem, &s->fe, DR_REG_FE_BASE); + + qdev_realize(DEVICE(&s->efuse), &s->periph_bus, &error_fatal); + esp32_soc_add_periph_device(sys_mem, &s->efuse, DR_REG_EFUSE_BASE); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->efuse), 0, + qdev_get_gpio_in(intmatrix_dev, ETS_EFUSE_INTR_SOURCE)); + + qdev_realize(DEVICE(&s->flash_enc), &s->periph_bus, &error_abort); + esp32_soc_add_periph_device(sys_mem, &s->flash_enc, DR_REG_SPI_ENCRYPT_BASE); + + qdev_connect_gpio_out_named(DEVICE(&s->efuse), ESP32_EFUSE_UPDATE_GPIO, 0, + qdev_get_gpio_in_named(DEVICE(&s->flash_enc), ESP32_FLASH_ENCRYPTION_EFUSE_UPDATE_GPIO, 0)); + qdev_connect_gpio_out_named(DEVICE(&s->dport), ESP32_DPORT_FLASH_ENC_EN_GPIO, 0, + qdev_get_gpio_in_named(DEVICE(&s->flash_enc), ESP32_FLASH_ENCRYPTION_ENC_EN_GPIO, 0)); + qdev_connect_gpio_out_named(DEVICE(&s->dport), ESP32_DPORT_FLASH_DEC_EN_GPIO, 0, + qdev_get_gpio_in_named(DEVICE(&s->flash_enc), ESP32_FLASH_ENCRYPTION_DEC_EN_GPIO, 0)); + + qdev_realize(DEVICE(&s->sdmmc), &s->periph_bus, &error_abort); + esp32_soc_add_periph_device(sys_mem, &s->sdmmc, DR_REG_SDMMC_BASE); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdmmc), 0, + qdev_get_gpio_in(intmatrix_dev, ETS_SDIO_HOST_INTR_SOURCE)); + + // not mentioned in fork + esp32_soc_add_unimp_default_device(sys_mem, "esp32.pcnt", DR_REG_PCNT_BASE, 0x1000, 0); + + // implemented in fork, still unimplemented here + esp32_soc_add_unimp_default_device(sys_mem, "esp32.rtcio", DR_REG_SENS_BASE, 0x400, 0); + esp32_soc_add_unimp_default_device(sys_mem, "esp32.rmt", DR_REG_RMT_BASE, 0x1000, 0); + + // common + esp32_soc_add_unimp_default_device(sys_mem, "esp32.rtcio", DR_REG_RTCIO_BASE, 0x400, 0); + esp32_soc_add_unimp_default_device(sys_mem, "esp32.iomux", DR_REG_IO_MUX_BASE, 0x2000, 0); + esp32_soc_add_unimp_default_device(sys_mem, "esp32.hinf", DR_REG_HINF_BASE, 0x100, 0); + esp32_soc_add_unimp_default_device(sys_mem, "esp32.slc", DR_REG_SLC_BASE, 0x1000, 0); + esp32_soc_add_unimp_default_device(sys_mem, "esp32.slchost", DR_REG_SLCHOST_BASE, 0x1000, 0); + esp32_soc_add_unimp_default_device(sys_mem, "esp32.apbctrl", DR_REG_APB_CTRL_BASE, 0x1000, 0); + esp32_soc_add_unimp_default_device(sys_mem, "esp32.i2s0", DR_REG_I2S_BASE, 0x1000, 0); + esp32_soc_add_unimp_default_device(sys_mem, "esp32.i2s1", DR_REG_I2S1_BASE, 0x1000, 0); + + // only implemented in fork + esp32_soc_add_unimp_default_device(sys_mem, "esp32.fe2", DR_REG_FE2_BASE, 0x1000, -1); + esp32_soc_add_unimp_default_device(sys_mem, "esp32.chipv7_phy", DR_REG_PHY_BASE, 0x1000, -1); + esp32_soc_add_unimp_default_device(sys_mem, "esp32.chipv7_phyb", DR_REG_WDEV_BASE, 0x1000, 0); + esp32_soc_add_unimp_default_device(sys_mem, "esp32.unknown_wifi", DR_REG_NRX_BASE , 0x1000, -1); + esp32_soc_add_unimp_default_device(sys_mem, "esp32.unknown_wifi1", DR_REG_BB_BASE , 0x1000, -1); + + /* Emulation of APB_CTRL_DATE_REG, needed for ECO3 revision detection. + * This is a small hack to avoid creating a whole new device just to emulate one + * register. + */ + const hwaddr apb_ctrl_date_reg = DR_REG_APB_CTRL_BASE + 0x7c; + MemoryRegion *apbctrl_mem = g_new(MemoryRegion, 1); + memory_region_init_ram(apbctrl_mem, NULL, "esp32.apbctrl_date_reg", 4 /* bytes */, &error_fatal); + memory_region_add_subregion(sys_mem, apb_ctrl_date_reg, apbctrl_mem); + uint32_t apb_ctrl_date_reg_val = 0x16042000 | 0x80000000; /* MSB indicates ECO3 silicon revision */ + cpu_physical_memory_write(apb_ctrl_date_reg, &apb_ctrl_date_reg_val, 4); + + qemu_register_reset((QEMUResetHandler*) esp32_soc_reset, dev); +} + +static void esp32_soc_init(Object *obj) +{ + Esp32SocState *s = ESP32_SOC(obj); + MachineState *ms = MACHINE(qdev_get_machine()); + char name[16]; + + MemoryRegion *system_memory = get_system_memory(); + + qbus_init(&s->periph_bus, sizeof(s->periph_bus), + TYPE_SYSTEM_BUS, DEVICE(s), "esp32-periph-bus"); + qbus_init(&s->rtc_bus, sizeof(s->rtc_bus), + TYPE_SYSTEM_BUS, DEVICE(s), "esp32-rtc-bus"); + + for (int i = 0; i < ms->smp.cpus; ++i) { + snprintf(name, sizeof(name), "cpu%d", i); + object_initialize_child(obj, name, &s->cpu[i], TYPE_ESP32_CPU); + + const uint32_t cpuid[ESP32_CPU_COUNT] = { 0xcdcd, 0xabab }; + s->cpu[i].env.sregs[PRID] = cpuid[i]; + + snprintf(name, sizeof(name), "cpu%d-mem", i); + memory_region_init(&s->cpu_specific_mem[i], NULL, name, UINT32_MAX); + + CPUState* cs = CPU(&s->cpu[i]); + cs->num_ases = 1; + cpu_address_space_init(cs, 0, "cpu-memory", &s->cpu_specific_mem[i]); + + MemoryRegion *cpu_view_sysmem = g_new(MemoryRegion, 1); + snprintf(name, sizeof(name), "cpu%d-sysmem", i); + memory_region_init_alias(cpu_view_sysmem, NULL, name, system_memory, 0, UINT32_MAX); + memory_region_add_subregion_overlap(&s->cpu_specific_mem[i], 0, cpu_view_sysmem, 0); + cs->memory = &s->cpu_specific_mem[i]; + } + + for (int i = 0; i < ESP32_UART_COUNT; ++i) { + snprintf(name, sizeof(name), "uart%d", i); + object_initialize_child(obj, name, &s->uart[i], TYPE_ESP32_UART); + } + + object_property_add_alias(obj, "serial0", OBJECT(&s->uart[0]), "chardev"); + object_property_add_alias(obj, "serial1", OBJECT(&s->uart[1]), "chardev"); + object_property_add_alias(obj, "serial2", OBJECT(&s->uart[2]), "chardev"); + + object_initialize_child(obj, "gpio", &s->gpio, TYPE_ESP32_GPIO); + + object_initialize_child(obj, "dport", &s->dport, TYPE_ESP32_DPORT); + + object_initialize_child(obj, "intmatrix", &s->intmatrix, TYPE_ESP32_INTMATRIX); + + object_initialize_child(obj, "crosscore_int", &s->crosscore_int, TYPE_ESP32_CROSSCORE_INT); + + object_initialize_child(obj, "rtc_cntl", &s->rtc_cntl, TYPE_ESP32_RTC_CNTL); + + for (int i = 0; i < ESP32_FRC_COUNT; ++i) { + snprintf(name, sizeof(name), "frc%d", i); + object_initialize_child(obj, name, &s->frc_timer[i], TYPE_ESP32_FRC_TIMER); + } + + for (int i = 0; i < ESP32_TIMG_COUNT; ++i) { + snprintf(name, sizeof(name), "timg%d", i); + object_initialize_child(obj, name, &s->timg[i], TYPE_ESP32_TIMG); + } + + for (int i = 0; i < ESP32_SPI_COUNT; ++i) { + snprintf(name, sizeof(name), "spi%d", i); + object_initialize_child(obj, name, &s->spi[i], TYPE_ESP32_SPI); + } + + for (int i = 0; i < ESP32_I2C_COUNT; ++i) { + snprintf(name, sizeof(name), "i2c%d", i); + object_initialize_child(obj, name, &s->i2c[i], TYPE_ESP32_I2C); + } + + object_initialize_child(obj, "rng", &s->rng, TYPE_ESP32_RNG); + + object_initialize_child(obj, "sha", &s->sha, TYPE_ESP32_SHA); + + object_initialize_child(obj, "unknown", &s->unknown, TYPE_ESP32_UNKNOWN); + + object_initialize_child(obj, "ana", &s->ana, TYPE_ESP32_ANA); + + printf("nb_nics=%d\n", nb_nics); + for(int i=0;iwifi, TYPE_ESP32_WIFI); + } + } + object_initialize_child(obj, "fe", &s->fe, TYPE_ESP32_FE); + + object_initialize_child(obj, "phya", &s->phya, TYPE_ESP32_PHYA); + + object_initialize_child(obj, "aes", &s->aes, TYPE_ESP32_AES); + + object_initialize_child(obj, "ledc", &s->ledc, TYPE_ESP32_LEDC); + + object_initialize_child(obj, "rsa", &s->rsa, TYPE_ESP32_RSA); + + object_initialize_child(obj, "efuse", &s->efuse, TYPE_ESP32_EFUSE); + + object_initialize_child(obj, "flash_enc", &s->flash_enc, TYPE_ESP32_FLASH_ENCRYPTION); + + object_initialize_child(obj, "sdmmc", &s->sdmmc, TYPE_DWC_SDMMC); + + qdev_init_gpio_in_named(DEVICE(s), esp32_dig_reset, ESP32_RTC_DIG_RESET_GPIO, 1); + qdev_init_gpio_in_named(DEVICE(s), esp32_cpu_reset, ESP32_RTC_CPU_RESET_GPIO, ESP32_CPU_COUNT); + qdev_init_gpio_in_named(DEVICE(s), esp32_cpu_stall, ESP32_RTC_CPU_STALL_GPIO, ESP32_CPU_COUNT); + qdev_init_gpio_in_named(DEVICE(s), esp32_clk_update, ESP32_RTC_CLK_UPDATE_GPIO, 1); + qdev_init_gpio_in_named(DEVICE(s), esp32_timg_cpu_reset, ESP32_TIMG_WDT_CPU_RESET_GPIO, 2); + qdev_init_gpio_in_named(DEVICE(s), esp32_timg_sys_reset, ESP32_TIMG_WDT_SYS_RESET_GPIO, 2); +} + +static Property esp32_soc_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32_soc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = esp32_soc_realize; + device_class_set_props(dc, esp32_soc_properties); +} + +static const TypeInfo esp32_soc_info = { + .name = TYPE_ESP32_SOC, + .parent = TYPE_DEVICE, + .instance_size = sizeof(Esp32SocState), + .instance_init = esp32_soc_init, + .class_init = esp32_soc_class_init +}; + +static void esp32_soc_register_types(void) +{ + type_register_static(&esp32_soc_info); +} + +type_init(esp32_soc_register_types) + + +static uint64_t translate_phys_addr(void *opaque, uint64_t addr) +{ + XtensaCPU *cpu = opaque; + + return cpu_get_phys_page_debug(CPU(cpu), addr); +} + + +struct Esp32MachineState { + MachineState parent; + + Esp32SocState esp32; + DeviceState *flash_dev; +}; +#define TYPE_ESP32_MACHINE MACHINE_TYPE_NAME("esp32") + +OBJECT_DECLARE_SIMPLE_TYPE(Esp32MachineState, ESP32_MACHINE) + + +static void esp32_machine_init_spi_flash(Esp32SocState *ss, BlockBackend* blk) +{ + /* "main" flash chip is attached to SPI1, CS0 */ + DeviceState *spi_master = DEVICE(&ss->spi[1]); + BusState* spi_bus = qdev_get_child_bus(spi_master, "spi"); + + /* select the flash chip based on the image size */ + int64_t image_size = blk_getlength(blk); + const char* flash_chip_model = NULL; + switch (image_size) { + case 2 * 1024 * 1024: flash_chip_model = "w25x16"; break; + case 4 * 1024 * 1024: flash_chip_model = "gd25q32"; break; + case 8 * 1024 * 1024: flash_chip_model = "gd25q64"; break; + case 16 * 1024 * 1024: flash_chip_model = "is25lp128"; break; + default: error_report("Error: only 2, 4, 8, 16 MB flash images are supported"); return; + } + + DeviceState *flash_dev = qdev_new(flash_chip_model); + qdev_prop_set_drive(flash_dev, "drive", blk); + qdev_realize_and_unref(flash_dev, spi_bus, &error_fatal); + qdev_connect_gpio_out_named(spi_master, SSI_GPIO_CS, 0, + qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0)); +} + +static void esp32_machine_init_psram(Esp32SocState *ss, uint32_t size_mbytes) +{ + /* PSRAM attached to SPI1, CS1 */ + DeviceState *spi_master = DEVICE(&ss->spi[1]); + BusState* spi_bus = qdev_get_child_bus(spi_master, "spi"); + DeviceState *psram = qdev_new(TYPE_SSI_PSRAM); + qdev_prop_set_uint32(psram, "size_mbytes", size_mbytes); + qdev_realize_and_unref(psram, spi_bus, &error_fatal); + qdev_connect_gpio_out_named(spi_master, SSI_GPIO_CS, 1, + qdev_get_gpio_in_named(psram, SSI_GPIO_CS, 0)); +} + +static void esp32_machine_init_i2c(Esp32SocState *s) +{ + /* It should be possible to create an I2C device from the command line, + * however for this to work the I2C bus must be reachable from sysbus-default. + * At the moment the peripherals are added to an unrelated bus, to avoid being + * reset on CPU reset. + * If we find a way to decouple peripheral reset from sysbus reset, + * we can move them to the sysbus and thus enable creation of i2c devices. + */ + DeviceState *i2c_master = DEVICE(&s->i2c[0]); + I2CBus* i2c_bus = I2C_BUS(qdev_get_child_bus(i2c_master, "i2c")); + I2CSlave* tmp105 = i2c_slave_create_simple(i2c_bus, "tmp105", 0x48); + object_property_set_int(OBJECT(tmp105), "temperature", 25 * 1000, &error_fatal); +} + +static void esp32_machine_init_openeth(Esp32SocState *ss) +{ + SysBusDevice *sbd; + MemoryRegion* sys_mem = get_system_memory(); + hwaddr reg_base = DR_REG_EMAC_BASE; + hwaddr desc_base = reg_base + 0x400; + qemu_irq irq = qdev_get_gpio_in(DEVICE(&ss->intmatrix), ETS_ETH_MAC_INTR_SOURCE); + + const char* type_openeth = "open_eth"; + for(int i=0;i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + + if (nd->used && nd->model && strcmp(nd->model, type_openeth) == 0) { + DeviceState* open_eth_dev = qdev_new(type_openeth); + ss->eth = open_eth_dev; + qdev_set_nic_properties(open_eth_dev, nd); + sbd = SYS_BUS_DEVICE(open_eth_dev); + sysbus_realize_and_unref(sbd, &error_fatal); + sysbus_connect_irq(sbd, 0, irq); + memory_region_add_subregion(sys_mem, reg_base, sysbus_mmio_get_region(sbd, 0)); + memory_region_add_subregion(sys_mem, desc_base, sysbus_mmio_get_region(sbd, 1)); + } + else if (nd->used && nd->model && strcmp(nd->model, TYPE_ESP32_WIFI) == 0) { + qdev_set_nic_properties(DEVICE(&ss->wifi), nd); + sbd = SYS_BUS_DEVICE(DEVICE(&ss->wifi)); + sysbus_realize_and_unref(sbd, &error_fatal); + esp32_soc_add_periph_device(sys_mem, &ss->wifi, DR_REG_WIFI_BASE); + sysbus_connect_irq(SYS_BUS_DEVICE(&ss->wifi), 0, + qdev_get_gpio_in(DEVICE(&ss->intmatrix), ETS_WIFI_MAC_INTR_SOURCE)); + } + } +} + +static void esp32_machine_init_sd(Esp32SocState *ss) +{ + DriveInfo *dinfo = drive_get(IF_SD, 0, 0); + if (dinfo) { + DeviceState *card; + + card = qdev_new(TYPE_SD_CARD); + qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo), + &error_fatal); + /* See the comment on not using sysbus-default in esp32_machine_init_i2c */ + DeviceState *sdmmc = DEVICE(&ss->sdmmc); + SDBus* sd_bus = SD_BUS(qdev_get_child_bus(sdmmc, "sd-bus")); + qdev_realize_and_unref(card, BUS(sd_bus), &error_fatal); + } +} + +static void esp32_machine_init(MachineState *machine) +{ + BlockBackend* blk = NULL; + DriveInfo *dinfo = drive_get(IF_MTD, 0, 0); + if (dinfo) { + qemu_log("Adding SPI flash device\n"); + blk = blk_by_legacy_dinfo(dinfo); + } else { + qemu_log("Not initializing SPI Flash\n"); + } + + Esp32MachineState *ms = ESP32_MACHINE(machine); + object_initialize_child(OBJECT(ms), "soc", &ms->esp32, TYPE_ESP32_SOC); + Esp32SocState *ss = ESP32_SOC(&ms->esp32); + + if (blk) { + ss->dport.flash_blk = blk; + } + qdev_prop_set_chr(DEVICE(ss), "serial0", serial_hd(0)); + qdev_prop_set_chr(DEVICE(ss), "serial1", serial_hd(1)); + qdev_prop_set_chr(DEVICE(ss), "serial2", serial_hd(2)); + if (machine->ram_size > 0) { + qdev_prop_set_bit(DEVICE(&ss->dport), "has_psram", true); + } + + qdev_realize(DEVICE(ss), NULL, &error_fatal); + + if (blk) { + esp32_machine_init_spi_flash(ss, blk); + } + + if (machine->ram_size > 0) { + esp32_machine_init_psram(ss, (uint32_t) (machine->ram_size / MiB)); + } + + esp32_machine_init_i2c(ss); + + esp32_machine_init_openeth(ss); + + esp32_machine_init_sd(ss); + + /* Need MMU initialized prior to ELF loading, + * so that ELF gets loaded into virtual addresses + */ + cpu_reset(CPU(&ss->cpu[0])); + + const char *load_elf_filename = NULL; + if (machine->firmware) { + load_elf_filename = machine->firmware; + } + if (machine->kernel_filename) { + qemu_log("Warning: both -bios and -kernel arguments specified. Only loading the the -kernel file.\n"); + load_elf_filename = machine->kernel_filename; + } + + if (load_elf_filename) { + uint64_t elf_entry; + uint64_t elf_lowaddr; + int size = load_elf(load_elf_filename, NULL, + translate_phys_addr, &ss->cpu[0], + &elf_entry, &elf_lowaddr, + NULL, NULL, 0, EM_XTENSA, 0, 0); + if (size < 0) { + error_report("Error: could not load ELF file '%s'", load_elf_filename); + exit(1); + } + + if (elf_entry != XCHAL_RESET_VECTOR_PADDR) { + // Since ROM is empty when loading elf file AND + // PC value is 0x40000400 after reset + // need to jump to elf entry point to run a programm + uint8_t p[4]; + memcpy(p, &elf_entry, 4); + uint8_t boot[] = { + 0x06, 0x01, 0x00, /* j 1 */ + 0x00, /* .literal_position */ + p[0], p[1], p[2], p[3], /* .literal elf_entry */ + /* 1: */ + 0x01, 0xff, 0xff, /* l32r a0, elf_entry */ + 0xa0, 0x00, 0x00, /* jx a0 */ + }; + // Write boot function to reset-vector address (0x40000400) of the CPU 0 + rom_add_blob_fixed_as("boot", boot, sizeof(boot), XCHAL_RESET_VECTOR_PADDR, CPU(&ss->cpu[0])->as); + ss->cpu[0].env.pc = XCHAL_RESET_VECTOR_PADDR; + } + } else { + char *rom_binary = qemu_find_file(QEMU_FILE_TYPE_BIOS, "esp32-v3-rom.bin"); + if (rom_binary == NULL) { + error_report("Error: -bios argument not set, and ROM code binary not found (1)"); + exit(1); + } + + int size = load_image_targphys_as(rom_binary, esp32_memmap[ESP32_MEMREGION_IROM].base, esp32_memmap[ESP32_MEMREGION_IROM].size, CPU(&ss->cpu[0])->as); + if (size < 0) { + error_report("Error: could not load ROM binary '%s'", rom_binary); + exit(1); + } + g_free(rom_binary); + + rom_binary = qemu_find_file(QEMU_FILE_TYPE_BIOS, "esp32-v3-rom-app.bin"); + if (rom_binary == NULL) { + error_report("Error: -bios argument not set, and ROM code binary not found (2)"); + exit(1); + } + + size = load_image_targphys_as(rom_binary, esp32_memmap[ESP32_MEMREGION_IROM].base, esp32_memmap[ESP32_MEMREGION_IROM].size, CPU(&ss->cpu[1])->as); + if (size < 0) { + error_report("Error: could not load ROM binary '%s'", rom_binary); + exit(1); + } + g_free(rom_binary); + } +} + +static ram_addr_t esp32_fixup_ram_size(ram_addr_t requested_size) +{ + ram_addr_t size; + if (requested_size == 0) { + size = 0; + } else if (requested_size <= 2 * MiB) { + size = 2 * MiB; + } else if (requested_size <= 4 * MiB ) { + size = 4 * MiB; + } else { + qemu_log("RAM size larger than 4 MB not supported\n"); + size = 4 * MiB; + } + return size; +} + +/* Initialize machine type */ +static void esp32_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + mc->desc = "Espressif ESP32 machine"; + mc->init = esp32_machine_init; + mc->max_cpus = 2; + mc->default_cpus = 2; + mc->default_ram_size = 0; + mc->fixup_ram_size = esp32_fixup_ram_size; +} + +static const TypeInfo esp32_info = { + .name = TYPE_ESP32_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(Esp32MachineState), + .class_init = esp32_machine_class_init, +}; + +static void esp32_machine_type_init(void) +{ + type_register_static(&esp32_info); +} + +type_init(esp32_machine_type_init); diff --git a/hw/xtensa/esp32_intc.c b/hw/xtensa/esp32_intc.c new file mode 100644 index 000000000000..50fb8f661d77 --- /dev/null +++ b/hw/xtensa/esp32_intc.c @@ -0,0 +1,155 @@ +/* + * ESP32 Interrupt Matrix + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/xtensa/esp32_intc.h" + +#define INTMATRIX_UNINT_VALUE 6 + +#define IRQ_MAP(cpu, input) s->irq_map[cpu][input] + +static void esp32_intmatrix_irq_handler(void *opaque, int n, int level) +{ + Esp32IntMatrixState *s = ESP32_INTMATRIX(opaque); + s->irq_raw[n] = level; + for (int i = 0; i < ESP32_CPU_COUNT; ++i) { + if (s->outputs[i] == NULL) { + continue; + } + int out_index = IRQ_MAP(i, n); + for (int int_index = 0; int_index < s->cpu[i]->env.config->nextint; ++int_index) { + if (s->cpu[i]->env.config->extint[int_index] == out_index) { + qemu_set_irq(s->outputs[i][int_index], level); + break; + } + } + } +} + +static inline uint8_t* get_map_entry(Esp32IntMatrixState* s, hwaddr addr) +{ + int source_index = addr / sizeof(uint32_t); + if (source_index > ESP32_INT_MATRIX_INPUTS * ESP32_CPU_COUNT) { + error_report("%s: source_index %d out of range", __func__, source_index); + return NULL; + } + int cpu_index = source_index / ESP32_INT_MATRIX_INPUTS; + source_index = source_index % ESP32_INT_MATRIX_INPUTS; + return &IRQ_MAP(cpu_index, source_index); +} + +static uint64_t esp32_intmatrix_read(void* opaque, hwaddr addr, unsigned int size) +{ + Esp32IntMatrixState *s = ESP32_INTMATRIX(opaque); + uint8_t* map_entry = get_map_entry(s, addr); + return (map_entry != NULL) ? *map_entry : 0; +} + +static void esp32_intmatrix_write(void* opaque, hwaddr addr, uint64_t value, unsigned int size) +{ + Esp32IntMatrixState *s = ESP32_INTMATRIX(opaque); + int source_index = (addr / sizeof(uint32_t)) % ESP32_INT_MATRIX_INPUTS; + uint8_t *map_entry = get_map_entry(s, addr); + if (value == INTMATRIX_UNINT_VALUE) { + int si = s->irq_raw[source_index]; + esp32_intmatrix_irq_handler(s, source_index, 0); + s->irq_raw[source_index] = si; + } + if (map_entry != NULL) { + *map_entry = value & 0x1f; + } + if (value != INTMATRIX_UNINT_VALUE && s->irq_raw[source_index]) { + esp32_intmatrix_irq_handler(s, source_index, 1); + } + +} + +static const MemoryRegionOps esp_intmatrix_ops = { + .read = esp32_intmatrix_read, + .write = esp32_intmatrix_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_intmatrix_reset(DeviceState *dev) +{ + Esp32IntMatrixState *s = ESP32_INTMATRIX(dev); + memset(s->irq_raw, 0, sizeof(s->irq_raw)); + memset(s->irq_map, INTMATRIX_UNINT_VALUE, sizeof(s->irq_map)); + for (int i = 0; i < ESP32_CPU_COUNT; ++i) { + if (s->outputs[i] == NULL) { + continue; + } + for (int int_index = 0; int_index < s->cpu[i]->env.config->nextint; ++int_index) { + qemu_irq_lower(s->outputs[i][int_index]); + } + } + +} + +static void esp32_intmatrix_realize(DeviceState *dev, Error **errp) +{ + Esp32IntMatrixState *s = ESP32_INTMATRIX(dev); + + for (int i = 0; i < ESP32_CPU_COUNT; ++i) { + if (s->cpu[i]) { + s->outputs[i] = xtensa_get_extints(&s->cpu[i]->env); + } + } + esp32_intmatrix_reset(dev); +} + +static void esp32_intmatrix_init(Object *obj) +{ + Esp32IntMatrixState *s = ESP32_INTMATRIX(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp_intmatrix_ops, s, + TYPE_ESP32_INTMATRIX, ESP32_INT_MATRIX_INPUTS * ESP32_CPU_COUNT * sizeof(uint32_t)); + sysbus_init_mmio(sbd, &s->iomem); + + qdev_init_gpio_in(DEVICE(s), esp32_intmatrix_irq_handler, ESP32_INT_MATRIX_INPUTS); +} + +static Property esp32_intmatrix_properties[] = { + DEFINE_PROP_LINK("cpu0", Esp32IntMatrixState, cpu[0], TYPE_XTENSA_CPU, XtensaCPU *), + DEFINE_PROP_LINK("cpu1", Esp32IntMatrixState, cpu[1], TYPE_XTENSA_CPU, XtensaCPU *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void esp32_intmatrix_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = esp32_intmatrix_reset; + dc->realize = esp32_intmatrix_realize; + device_class_set_props(dc, esp32_intmatrix_properties); +} + +static const TypeInfo esp32_intmatrix_info = { + .name = TYPE_ESP32_INTMATRIX, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32IntMatrixState), + .instance_init = esp32_intmatrix_init, + .class_init = esp32_intmatrix_class_init +}; + +static void esp32_intmatrix_register_types(void) +{ + type_register_static(&esp32_intmatrix_info); +} + +type_init(esp32_intmatrix_register_types) diff --git a/hw/xtensa/meson.build b/hw/xtensa/meson.build index 1d5835df4bf4..695f15bd4271 100644 --- a/hw/xtensa/meson.build +++ b/hw/xtensa/meson.build @@ -7,5 +7,6 @@ xtensa_ss.add(files( xtensa_ss.add(when: 'CONFIG_XTENSA_SIM', if_true: files('sim.c')) xtensa_ss.add(when: 'CONFIG_XTENSA_VIRT', if_true: files('virt.c')) xtensa_ss.add(when: 'CONFIG_XTENSA_XTFPGA', if_true: files('xtfpga.c')) +xtensa_ss.add(when: 'CONFIG_XTENSA_ESP32', if_true: files('esp32.c', 'esp32_intc.c')) hw_arch += {'xtensa': xtensa_ss} diff --git a/include/hw/char/esp32_uart.h b/include/hw/char/esp32_uart.h new file mode 100644 index 000000000000..f46af5303bef --- /dev/null +++ b/include/hw/char/esp32_uart.h @@ -0,0 +1,106 @@ +#pragma once + +#include "qemu/fifo8.h" +#include "hw/sysbus.h" +#include "chardev/char-fe.h" +#include "hw/hw.h" +#include "hw/registerfields.h" + +#define UART_FIFO_LENGTH 128 + +#define TYPE_ESP32_UART "esp_soc.uart" +#define ESP32_UART_GET_CLASS(obj) OBJECT_GET_CLASS(ESP32UARTClass, obj, TYPE_ESP32_UART) +#define ESP32_UART_CLASS(klass) OBJECT_CLASS_CHECK(ESP32UARTClass, klass, TYPE_ESP32_UART) +#define ESP32_UART(obj) OBJECT_CHECK(ESP32UARTState, (obj), TYPE_ESP32_UART) + +REG32(UART_FIFO, 0x0) +REG32(UART_INT_RAW, 0x4) + FIELD(UART_INT_RAW, RXFIFO_FULL, 0, 1) + FIELD(UART_INT_RAW, TXFIFO_EMPTY, 1, 1) + FIELD(UART_INT_RAW, RXFIFO_OVF, 4, 1) + FIELD(UART_INT_RAW, RXFIFO_TOUT, 8, 1) + FIELD(UART_INT_RAW, TX_DONE, 14, 1) +REG32(UART_INT_ST, 0x8) + FIELD(UART_INT_ST, RXFIFO_FULL, 0, 1) + FIELD(UART_INT_ST, TXFIFO_EMPTY, 1, 1) + FIELD(UART_INT_ST, RXFIFO_OVF, 4, 1) + FIELD(UART_INT_ST, RXFIFO_TOUT, 8, 1) + FIELD(UART_INT_ST, TX_DONE, 14, 1) +REG32(UART_INT_ENA, 0xC) + FIELD(UART_INT_ENA, RXFIFO_FULL, 0, 1) + FIELD(UART_INT_ENA, TXFIFO_EMPTY, 1, 1) + FIELD(UART_INT_ENA, RXFIFO_OVF, 4, 1) + FIELD(UART_INT_ENA, RXFIFO_TOUT, 8, 1) + FIELD(UART_INT_ENA, TX_DONE, 14, 1) +REG32(UART_INT_CLR, 0x10) + FIELD(UART_INT_CLR, RXFIFO_FULL, 0, 1) + FIELD(UART_INT_CLR, TXFIFO_EMPTY, 1, 1) + FIELD(UART_INT_CLR, RXFIFO_OVF, 4, 1) + FIELD(UART_INT_CLR, RXFIFO_TOUT, 8, 1) + FIELD(UART_INT_CLR, TX_DONE, 14, 1) + +/* TODO: implement */ +REG32(UART_CLKDIV, 0x14) + FIELD(UART_CLKDIV, CLKDIV, 0, 20) + FIELD(UART_CLKDIV, CLKDIV_FRAG, 20, 4) + +REG32(UART_AUTOBAUD, 0x18) + FIELD(UART_AUTOBAUD, EN, 0, 1) + +REG32(UART_STATUS, 0x1C) + FIELD(UART_STATUS, RXFIFO_CNT, 0, 8) + FIELD(UART_STATUS, ST_URX_OUT, 8, 4) + FIELD(UART_STATUS, TXFIFO_CNT, 16, 8) + FIELD(UART_STATUS, ST_UTX_OUT, 24, 4) + +REG32(UART_LOWPULSE, 0x28) +REG32(UART_HIGHPULSE, 0x2c) +REG32(UART_RXD_CNT, 0x30) + +/* TODO: implement */ +REG32(UART_CONF0, 0x20) +REG32(UART_CONF1, 0x24) + FIELD(UART_CONF1, TOUT_EN, 31, 1) + FIELD(UART_CONF1, TOUT_THRD, 24, 7) + FIELD(UART_CONF1, TXFIFO_EMPTY_THRD, 8, 7) + FIELD(UART_CONF1, RXFIFO_FULL_THRD, 0, 7) + +REG32(UART_MEM_CONF, 0x58); + FIELD(UART_MEM_CONF, RX_SIZE, 3, 4); + FIELD(UART_MEM_CONF, TX_SIZE, 7, 4); +REG32(UART_MEM_RX_STATUS, 0x60); + FIELD(UART_MEM_RX_STATUS, RD_ADDR, 2, 11); + FIELD(UART_MEM_RX_STATUS, WR_ADDR, 13, 11); +REG32(UART_DATE, 0x78) + +/* Size of the register file */ +#define UART_REG_CNT (R_UART_DATE + 1) + + +typedef struct ESPUARTState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + CharBackend chr; + qemu_irq irq; + QEMUTimer throttle_timer; + QEMUTimer rx_timeout_timer; + bool throttle_rx; + bool rxfifo_tout; + unsigned baud_rate; + + Fifo8 rx_fifo; + Fifo8 tx_fifo; + guint tx_watch_handle; + + uint32_t reg[UART_REG_CNT]; + MemoryRegionOps uart_ops; +} ESP32UARTState; + +typedef struct ESPUARTClass { + SysBusDeviceClass parent_class; + + /* Virtual attributes/methods */ + void (*uart_write)(void *opaque, hwaddr addr, uint64_t value, unsigned int size); + uint64_t (*uart_read)(void *opaque, hwaddr addr, unsigned int size); +} ESP32UARTClass; diff --git a/include/hw/char/esp32c3_uart.h b/include/hw/char/esp32c3_uart.h new file mode 100644 index 000000000000..38f56bd40b4a --- /dev/null +++ b/include/hw/char/esp32c3_uart.h @@ -0,0 +1,69 @@ +#pragma once + +#include "esp32_uart.h" + + +#define TYPE_ESP32C3_UART "esp32c3_soc.uart" +/* This macro can be used to "convert" a generic object into a more specific object, here ESP32C3UARTState. + * For example, it can convert a DeviceState to a ESP32C3UARTState */ +#define ESP32C3_UART(obj) OBJECT_CHECK(ESP32C3UARTState, (obj), TYPE_ESP32C3_UART) +/* This one can be used to get the class of a given object. + * For example, it can give the ESP32UARTClass type structure out of a DeviceState or a + * ESP32C3UARTState structure. */ +#define ESP32C3_UART_GET_CLASS(obj) OBJECT_GET_CLASS(ESP32C3UARTClass, obj, TYPE_ESP32C3_UART) +/* Finally, this macro is used to convert a generic class to ESP32C3UARTClass. + * For example, it can be used to convert an ObjectClass to a ESP32C3UARTClass*/ +#define ESP32C3_UART_CLASS(klass) OBJECT_CLASS_CHECK(ESP32C3UARTClass, klass, TYPE_ESP32C3_UART) + +typedef struct ESP32C3UARTState { + ESP32UARTState parent; + +} ESP32C3UARTState; + +typedef struct ESP32C3UARTClass { + ESP32UARTClass parent_class; + + /* These function pointers will be during class init, they will be populated + * by device_class_set_parent_* functions. They can then be called in the + * respective class methods: realize and reset. */ + DeviceRealize parent_realize; + DeviceReset parent_reset; + + /* Virtual attributes/methods overriden */ + void (*parent_uart_write)(void *opaque, hwaddr addr, uint64_t value, unsigned int size); + uint64_t (*parent_uart_read)(void *opaque, hwaddr addr, unsigned int size); +} ESP32C3UARTClass; + + +/** + * Define the ESP32-C3 specific registers, or the ones that saw their address or fields + * changed from the ESP32 UART + */ +REG32(ESP32C3_UART_CONF0, 0x20) + FIELD(ESP32C3_UART_CONF0, MEM_CLK_EN, 28, 1) + FIELD(ESP32C3_UART_CONF0, AUTOBAUD_EN, 27, 1) + FIELD(ESP32C3_UART_CONF0, ERR_WR_MASK, 26, 1) + FIELD(ESP32C3_UART_CONF0, CLK_EN, 25, 1) + FIELD(ESP32C3_UART_CONF0, DTR_INV, 24, 1) + FIELD(ESP32C3_UART_CONF0, RTS_INV, 23, 1) + FIELD(ESP32C3_UART_CONF0, TXD_INV, 22, 1) + FIELD(ESP32C3_UART_CONF0, DSR_INV, 21, 1) + FIELD(ESP32C3_UART_CONF0, CTS_INV, 20, 1) + FIELD(ESP32C3_UART_CONF0, RXD_INV, 19, 1) + FIELD(ESP32C3_UART_CONF0, TXFIFO_RST, 18, 1) + FIELD(ESP32C3_UART_CONF0, RXFIFO_RST, 17, 1) + FIELD(ESP32C3_UART_CONF0, IRDA_EN, 16, 1) + FIELD(ESP32C3_UART_CONF0, TX_FLOW_EN, 15, 1) + FIELD(ESP32C3_UART_CONF0, LOOPBACK, 14, 1) + FIELD(ESP32C3_UART_CONF0, IRDA_RX_INV, 13, 1) + FIELD(ESP32C3_UART_CONF0, IRDA_TX_INV, 12, 1) + FIELD(ESP32C3_UART_CONF0, IRDA_WCTL, 11, 1) + FIELD(ESP32C3_UART_CONF0, IRDA_TX_EN, 10, 1) + FIELD(ESP32C3_UART_CONF0, IRDA_DPLX, 9, 1) + FIELD(ESP32C3_UART_CONF0, TXD_BRK, 8, 1) + FIELD(ESP32C3_UART_CONF0, SW_DTR, 7, 1) + FIELD(ESP32C3_UART_CONF0, SW_RTS, 6, 1) + FIELD(ESP32C3_UART_CONF0, STOP_BIT_NUM, 4, 2) + FIELD(ESP32C3_UART_CONF0, BIT_NUM, 2, 2) + FIELD(ESP32C3_UART_CONF0, PARITY_EN, 1, 1) + FIELD(ESP32C3_UART_CONF0, PARITY, 0, 1) diff --git a/include/hw/dma/esp32c3_gdma.h b/include/hw/dma/esp32c3_gdma.h new file mode 100644 index 000000000000..c3191f489d3f --- /dev/null +++ b/include/hw/dma/esp32c3_gdma.h @@ -0,0 +1,653 @@ +/* + * ESP32-C3 GDMA emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/esp32c3_reg.h" + +#define TYPE_ESP32C3_GDMA "esp32c3.gdma" +#define ESP32C3_GDMA(obj) OBJECT_CHECK(ESP32C3GdmaState, (obj), TYPE_ESP32C3_GDMA) + +#define ESP32C3_GDMA_REGS_SIZE (A_DMA_OUT_PERI_SEL_CH2 + 4) + +#define ESP32C3_GDMA_CHANNEL_COUNT 3 + +#define ESP32C3_GDMA_IN_IDX 0 +#define ESP32C3_GDMA_OUT_IDX 1 +#define ESP32C3_GDMA_CONF_COUNT (ESP32C3_GDMA_OUT_IDX + 1) + +#define ESP32C3_GDMA_RAM_ADDR 0x3FC80000 + + +/** + * @brief Number for each peripheral that can access GDMA + */ +typedef enum { + GDMA_SPI2 = 0, + GDMA_RSVD1 = 1, + GDMA_UHCI0 = 2, + GDMA_I2S = 3, + GDMA_RSVD4 = 4, + GDMA_RSVD5 = 5, + GDMA_AES = 6, + GDMA_SHA = 7, + GDMA_ADC = 8, + GDMA_LAST = GDMA_ADC, +} GdmaPeripheral; + + +/** + * Size of the interrupt registers, in bytes, for a single channel + */ +#define ESP32C3_GDMA_INT_REGS_SIZE 0x10 + +typedef struct { + uint32_t raw; + uint32_t st; + uint32_t ena; + /* Not really necessary to have this variable here as it will never contain + * any data, but will simplify the code (offset calculation) */ + uint32_t clr; +} DmaIntState; + + +typedef struct { + uint32_t conf0; + uint32_t conf1; + uint32_t status; + uint32_t push_pop; + uint32_t link; + /* Status registers */ + uint32_t state; + uint32_t suc_eof_desc_addr; // Address of descriptor when EOF bit is 1 + uint32_t err_eof_desc_addr; // Address of descriptor when error occurs (UHCI0 only) + uint32_t desc_addr; // Address of the next descriptor (n + 1) + uint32_t bfr_desc_addr; // Address of the current descriptor (n) + uint32_t bfr_bfr_desc_addr; // Address of the previous descriptor (n - 1) + uint32_t priority; + uint32_t peripheral; +} DmaConfigState; + + +typedef struct ESP32C3GdmaState { + SysBusDevice parent_object; + MemoryRegion iomem; + qemu_irq irq[ESP32C3_GDMA_CHANNEL_COUNT]; + + DmaIntState ch_int[ESP32C3_GDMA_CHANNEL_COUNT]; + DmaConfigState ch_conf[ESP32C3_GDMA_CHANNEL_COUNT][ESP32C3_GDMA_CONF_COUNT]; + + /* Use this register mainly for enabling and disabling priorities */ + uint32_t misc_conf; + + /* Keep a pointer to the SoC DRAM */ + MemoryRegion* soc_mr; + AddressSpace dma_as; + +} ESP32C3GdmaState; + + +/** + * @brief Get the channel configured for the given peripheral + * + * @param s GDMA state + * @param periph Peripheral to search + * @param dir Direction from the GDMA point of view: ESP32C3_GDMA_IN_IDX or ESP32C3_GDMA_OUT_IDX. + * For example, to find a channel that needs to be written to, use ESP32C3_GDMA_IN_IDX + * (because GDMA receives the data) + * @param chan Returned channel index linked to the peripheral + * + * @returns index of the GDMA channel bound to the peripheral, -1 if not found + */ +bool esp32c3_gdma_get_channel_periph(ESP32C3GdmaState *s, GdmaPeripheral periph, int dir, + uint32_t* chan); + +bool esp32c3_gdma_read_channel(ESP32C3GdmaState *s, uint32_t chan, uint8_t* buffer, uint32_t size); +bool esp32c3_gdma_write_channel(ESP32C3GdmaState *s, uint32_t chan, uint8_t* buffer, uint32_t size); + +REG32(DMA_INT_RAW_CH0, 0x000) + FIELD(DMA_INT_RAW_CH0, OUTFIFO_UDF_CH0_INT_RAW, 12, 1) + FIELD(DMA_INT_RAW_CH0, OUTFIFO_OVF_CH0_INT_RAW, 11, 1) + FIELD(DMA_INT_RAW_CH0, INFIFO_UDF_CH0_INT_RAW, 10, 1) + FIELD(DMA_INT_RAW_CH0, INFIFO_OVF_CH0_INT_RAW, 9, 1) + FIELD(DMA_INT_RAW_CH0, OUT_TOTAL_EOF_CH0_INT_RAW, 8, 1) + FIELD(DMA_INT_RAW_CH0, IN_DSCR_EMPTY_CH0_INT_RAW, 7, 1) + FIELD(DMA_INT_RAW_CH0, OUT_DSCR_ERR_CH0_INT_RAW, 6, 1) + FIELD(DMA_INT_RAW_CH0, IN_DSCR_ERR_CH0_INT_RAW, 5, 1) + FIELD(DMA_INT_RAW_CH0, OUT_EOF_CH0_INT_RAW, 4, 1) + FIELD(DMA_INT_RAW_CH0, OUT_DONE_CH0_INT_RAW, 3, 1) + FIELD(DMA_INT_RAW_CH0, IN_ERR_EOF_CH0_INT_RAW, 2, 1) + FIELD(DMA_INT_RAW_CH0, IN_SUC_EOF_CH0_INT_RAW, 1, 1) + FIELD(DMA_INT_RAW_CH0, IN_DONE_CH0_INT_RAW, 0, 1) + +REG32(DMA_INT_ST_CH0, 0x004) + FIELD(DMA_INT_ST_CH0, OUTFIFO_UDF_CH0_INT_ST, 12, 1) + FIELD(DMA_INT_ST_CH0, OUTFIFO_OVF_CH0_INT_ST, 11, 1) + FIELD(DMA_INT_ST_CH0, INFIFO_UDF_CH0_INT_ST, 10, 1) + FIELD(DMA_INT_ST_CH0, INFIFO_OVF_CH0_INT_ST, 9, 1) + FIELD(DMA_INT_ST_CH0, OUT_TOTAL_EOF_CH0_INT_ST, 8, 1) + FIELD(DMA_INT_ST_CH0, IN_DSCR_EMPTY_CH0_INT_ST, 7, 1) + FIELD(DMA_INT_ST_CH0, OUT_DSCR_ERR_CH0_INT_ST, 6, 1) + FIELD(DMA_INT_ST_CH0, IN_DSCR_ERR_CH0_INT_ST, 5, 1) + FIELD(DMA_INT_ST_CH0, OUT_EOF_CH0_INT_ST, 4, 1) + FIELD(DMA_INT_ST_CH0, OUT_DONE_CH0_INT_ST, 3, 1) + FIELD(DMA_INT_ST_CH0, IN_ERR_EOF_CH0_INT_ST, 2, 1) + FIELD(DMA_INT_ST_CH0, IN_SUC_EOF_CH0_INT_ST, 1, 1) + FIELD(DMA_INT_ST_CH0, IN_DONE_CH0_INT_ST, 0, 1) + +REG32(DMA_INT_ENA_CH0, 0x008) + FIELD(DMA_INT_ENA_CH0, OUTFIFO_UDF_CH0_INT_ENA, 12, 1) + FIELD(DMA_INT_ENA_CH0, OUTFIFO_OVF_CH0_INT_ENA, 11, 1) + FIELD(DMA_INT_ENA_CH0, INFIFO_UDF_CH0_INT_ENA, 10, 1) + FIELD(DMA_INT_ENA_CH0, INFIFO_OVF_CH0_INT_ENA, 9, 1) + FIELD(DMA_INT_ENA_CH0, OUT_TOTAL_EOF_CH0_INT_ENA, 8, 1) + FIELD(DMA_INT_ENA_CH0, IN_DSCR_EMPTY_CH0_INT_ENA, 7, 1) + FIELD(DMA_INT_ENA_CH0, OUT_DSCR_ERR_CH0_INT_ENA, 6, 1) + FIELD(DMA_INT_ENA_CH0, IN_DSCR_ERR_CH0_INT_ENA, 5, 1) + FIELD(DMA_INT_ENA_CH0, OUT_EOF_CH0_INT_ENA, 4, 1) + FIELD(DMA_INT_ENA_CH0, OUT_DONE_CH0_INT_ENA, 3, 1) + FIELD(DMA_INT_ENA_CH0, IN_ERR_EOF_CH0_INT_ENA, 2, 1) + FIELD(DMA_INT_ENA_CH0, IN_SUC_EOF_CH0_INT_ENA, 1, 1) + FIELD(DMA_INT_ENA_CH0, IN_DONE_CH0_INT_ENA, 0, 1) + +REG32(DMA_INT_CLR_CH0, 0x00C) + FIELD(DMA_INT_CLR_CH0, OUTFIFO_UDF_CH0_INT_CLR, 12, 1) + FIELD(DMA_INT_CLR_CH0, OUTFIFO_OVF_CH0_INT_CLR, 11, 1) + FIELD(DMA_INT_CLR_CH0, INFIFO_UDF_CH0_INT_CLR, 10, 1) + FIELD(DMA_INT_CLR_CH0, INFIFO_OVF_CH0_INT_CLR, 9, 1) + FIELD(DMA_INT_CLR_CH0, OUT_TOTAL_EOF_CH0_INT_CLR, 8, 1) + FIELD(DMA_INT_CLR_CH0, IN_DSCR_EMPTY_CH0_INT_CLR, 7, 1) + FIELD(DMA_INT_CLR_CH0, OUT_DSCR_ERR_CH0_INT_CLR, 6, 1) + FIELD(DMA_INT_CLR_CH0, IN_DSCR_ERR_CH0_INT_CLR, 5, 1) + FIELD(DMA_INT_CLR_CH0, OUT_EOF_CH0_INT_CLR, 4, 1) + FIELD(DMA_INT_CLR_CH0, OUT_DONE_CH0_INT_CLR, 3, 1) + FIELD(DMA_INT_CLR_CH0, IN_ERR_EOF_CH0_INT_CLR, 2, 1) + FIELD(DMA_INT_CLR_CH0, IN_SUC_EOF_CH0_INT_CLR, 1, 1) + FIELD(DMA_INT_CLR_CH0, IN_DONE_CH0_INT_CLR, 0, 1) + +REG32(DMA_INT_RAW_CH1, 0x010) + FIELD(DMA_INT_RAW_CH1, OUTFIFO_UDF_CH1_INT_RAW, 12, 1) + FIELD(DMA_INT_RAW_CH1, OUTFIFO_OVF_CH1_INT_RAW, 11, 1) + FIELD(DMA_INT_RAW_CH1, INFIFO_UDF_CH1_INT_RAW, 10, 1) + FIELD(DMA_INT_RAW_CH1, INFIFO_OVF_CH1_INT_RAW, 9, 1) + FIELD(DMA_INT_RAW_CH1, OUT_TOTAL_EOF_CH1_INT_RAW, 8, 1) + FIELD(DMA_INT_RAW_CH1, IN_DSCR_EMPTY_CH1_INT_RAW, 7, 1) + FIELD(DMA_INT_RAW_CH1, OUT_DSCR_ERR_CH1_INT_RAW, 6, 1) + FIELD(DMA_INT_RAW_CH1, IN_DSCR_ERR_CH1_INT_RAW, 5, 1) + FIELD(DMA_INT_RAW_CH1, OUT_EOF_CH1_INT_RAW, 4, 1) + FIELD(DMA_INT_RAW_CH1, OUT_DONE_CH1_INT_RAW, 3, 1) + FIELD(DMA_INT_RAW_CH1, IN_ERR_EOF_CH1_INT_RAW, 2, 1) + FIELD(DMA_INT_RAW_CH1, IN_SUC_EOF_CH1_INT_RAW, 1, 1) + FIELD(DMA_INT_RAW_CH1, IN_DONE_CH1_INT_RAW, 0, 1) + +REG32(DMA_INT_ST_CH1, 0x014) + FIELD(DMA_INT_ST_CH1, OUTFIFO_UDF_CH1_INT_ST, 12, 1) + FIELD(DMA_INT_ST_CH1, OUTFIFO_OVF_CH1_INT_ST, 11, 1) + FIELD(DMA_INT_ST_CH1, INFIFO_UDF_CH1_INT_ST, 10, 1) + FIELD(DMA_INT_ST_CH1, INFIFO_OVF_CH1_INT_ST, 9, 1) + FIELD(DMA_INT_ST_CH1, OUT_TOTAL_EOF_CH1_INT_ST, 8, 1) + FIELD(DMA_INT_ST_CH1, IN_DSCR_EMPTY_CH1_INT_ST, 7, 1) + FIELD(DMA_INT_ST_CH1, OUT_DSCR_ERR_CH1_INT_ST, 6, 1) + FIELD(DMA_INT_ST_CH1, IN_DSCR_ERR_CH1_INT_ST, 5, 1) + FIELD(DMA_INT_ST_CH1, OUT_EOF_CH1_INT_ST, 4, 1) + FIELD(DMA_INT_ST_CH1, OUT_DONE_CH1_INT_ST, 3, 1) + FIELD(DMA_INT_ST_CH1, IN_ERR_EOF_CH1_INT_ST, 2, 1) + FIELD(DMA_INT_ST_CH1, IN_SUC_EOF_CH1_INT_ST, 1, 1) + FIELD(DMA_INT_ST_CH1, IN_DONE_CH1_INT_ST, 0, 1) + +REG32(DMA_INT_ENA_CH1, 0x018) + FIELD(DMA_INT_ENA_CH1, OUTFIFO_UDF_CH1_INT_ENA, 12, 1) + FIELD(DMA_INT_ENA_CH1, OUTFIFO_OVF_CH1_INT_ENA, 11, 1) + FIELD(DMA_INT_ENA_CH1, INFIFO_UDF_CH1_INT_ENA, 10, 1) + FIELD(DMA_INT_ENA_CH1, INFIFO_OVF_CH1_INT_ENA, 9, 1) + FIELD(DMA_INT_ENA_CH1, OUT_TOTAL_EOF_CH1_INT_ENA, 8, 1) + FIELD(DMA_INT_ENA_CH1, IN_DSCR_EMPTY_CH1_INT_ENA, 7, 1) + FIELD(DMA_INT_ENA_CH1, OUT_DSCR_ERR_CH1_INT_ENA, 6, 1) + FIELD(DMA_INT_ENA_CH1, IN_DSCR_ERR_CH1_INT_ENA, 5, 1) + FIELD(DMA_INT_ENA_CH1, OUT_EOF_CH1_INT_ENA, 4, 1) + FIELD(DMA_INT_ENA_CH1, OUT_DONE_CH1_INT_ENA, 3, 1) + FIELD(DMA_INT_ENA_CH1, IN_ERR_EOF_CH1_INT_ENA, 2, 1) + FIELD(DMA_INT_ENA_CH1, IN_SUC_EOF_CH1_INT_ENA, 1, 1) + FIELD(DMA_INT_ENA_CH1, IN_DONE_CH1_INT_ENA, 0, 1) + +REG32(DMA_INT_CLR_CH1, 0x01C) + FIELD(DMA_INT_CLR_CH1, OUTFIFO_UDF_CH1_INT_CLR, 12, 1) + FIELD(DMA_INT_CLR_CH1, OUTFIFO_OVF_CH1_INT_CLR, 11, 1) + FIELD(DMA_INT_CLR_CH1, INFIFO_UDF_CH1_INT_CLR, 10, 1) + FIELD(DMA_INT_CLR_CH1, INFIFO_OVF_CH1_INT_CLR, 9, 1) + FIELD(DMA_INT_CLR_CH1, OUT_TOTAL_EOF_CH1_INT_CLR, 8, 1) + FIELD(DMA_INT_CLR_CH1, IN_DSCR_EMPTY_CH1_INT_CLR, 7, 1) + FIELD(DMA_INT_CLR_CH1, OUT_DSCR_ERR_CH1_INT_CLR, 6, 1) + FIELD(DMA_INT_CLR_CH1, IN_DSCR_ERR_CH1_INT_CLR, 5, 1) + FIELD(DMA_INT_CLR_CH1, OUT_EOF_CH1_INT_CLR, 4, 1) + FIELD(DMA_INT_CLR_CH1, OUT_DONE_CH1_INT_CLR, 3, 1) + FIELD(DMA_INT_CLR_CH1, IN_ERR_EOF_CH1_INT_CLR, 2, 1) + FIELD(DMA_INT_CLR_CH1, IN_SUC_EOF_CH1_INT_CLR, 1, 1) + FIELD(DMA_INT_CLR_CH1, IN_DONE_CH1_INT_CLR, 0, 1) + +REG32(DMA_INT_RAW_CH2, 0x020) + FIELD(DMA_INT_RAW_CH2, OUTFIFO_UDF_CH2_INT_RAW, 12, 1) + FIELD(DMA_INT_RAW_CH2, OUTFIFO_OVF_CH2_INT_RAW, 11, 1) + FIELD(DMA_INT_RAW_CH2, INFIFO_UDF_CH2_INT_RAW, 10, 1) + FIELD(DMA_INT_RAW_CH2, INFIFO_OVF_CH2_INT_RAW, 9, 1) + FIELD(DMA_INT_RAW_CH2, OUT_TOTAL_EOF_CH2_INT_RAW, 8, 1) + FIELD(DMA_INT_RAW_CH2, IN_DSCR_EMPTY_CH2_INT_RAW, 7, 1) + FIELD(DMA_INT_RAW_CH2, OUT_DSCR_ERR_CH2_INT_RAW, 6, 1) + FIELD(DMA_INT_RAW_CH2, IN_DSCR_ERR_CH2_INT_RAW, 5, 1) + FIELD(DMA_INT_RAW_CH2, OUT_EOF_CH2_INT_RAW, 4, 1) + FIELD(DMA_INT_RAW_CH2, OUT_DONE_CH2_INT_RAW, 3, 1) + FIELD(DMA_INT_RAW_CH2, IN_ERR_EOF_CH2_INT_RAW, 2, 1) + FIELD(DMA_INT_RAW_CH2, IN_SUC_EOF_CH2_INT_RAW, 1, 1) + FIELD(DMA_INT_RAW_CH2, IN_DONE_CH2_INT_RAW, 0, 1) + +REG32(DMA_INT_ST_CH2, 0x024) + FIELD(DMA_INT_ST_CH2, OUTFIFO_UDF_CH2_INT_ST, 12, 1) + FIELD(DMA_INT_ST_CH2, OUTFIFO_OVF_CH2_INT_ST, 11, 1) + FIELD(DMA_INT_ST_CH2, INFIFO_UDF_CH2_INT_ST, 10, 1) + FIELD(DMA_INT_ST_CH2, INFIFO_OVF_CH2_INT_ST, 9, 1) + FIELD(DMA_INT_ST_CH2, OUT_TOTAL_EOF_CH2_INT_ST, 8, 1) + FIELD(DMA_INT_ST_CH2, IN_DSCR_EMPTY_CH2_INT_ST, 7, 1) + FIELD(DMA_INT_ST_CH2, OUT_DSCR_ERR_CH2_INT_ST, 6, 1) + FIELD(DMA_INT_ST_CH2, IN_DSCR_ERR_CH2_INT_ST, 5, 1) + FIELD(DMA_INT_ST_CH2, OUT_EOF_CH2_INT_ST, 4, 1) + FIELD(DMA_INT_ST_CH2, OUT_DONE_CH2_INT_ST, 3, 1) + FIELD(DMA_INT_ST_CH2, IN_ERR_EOF_CH2_INT_ST, 2, 1) + FIELD(DMA_INT_ST_CH2, IN_SUC_EOF_CH2_INT_ST, 1, 1) + FIELD(DMA_INT_ST_CH2, IN_DONE_CH2_INT_ST, 0, 1) + +REG32(DMA_INT_ENA_CH2, 0x028) + FIELD(DMA_INT_ENA_CH2, OUTFIFO_UDF_CH2_INT_ENA, 12, 1) + FIELD(DMA_INT_ENA_CH2, OUTFIFO_OVF_CH2_INT_ENA, 11, 1) + FIELD(DMA_INT_ENA_CH2, INFIFO_UDF_CH2_INT_ENA, 10, 1) + FIELD(DMA_INT_ENA_CH2, INFIFO_OVF_CH2_INT_ENA, 9, 1) + FIELD(DMA_INT_ENA_CH2, OUT_TOTAL_EOF_CH2_INT_ENA, 8, 1) + FIELD(DMA_INT_ENA_CH2, IN_DSCR_EMPTY_CH2_INT_ENA, 7, 1) + FIELD(DMA_INT_ENA_CH2, OUT_DSCR_ERR_CH2_INT_ENA, 6, 1) + FIELD(DMA_INT_ENA_CH2, IN_DSCR_ERR_CH2_INT_ENA, 5, 1) + FIELD(DMA_INT_ENA_CH2, OUT_EOF_CH2_INT_ENA, 4, 1) + FIELD(DMA_INT_ENA_CH2, OUT_DONE_CH2_INT_ENA, 3, 1) + FIELD(DMA_INT_ENA_CH2, IN_ERR_EOF_CH2_INT_ENA, 2, 1) + FIELD(DMA_INT_ENA_CH2, IN_SUC_EOF_CH2_INT_ENA, 1, 1) + FIELD(DMA_INT_ENA_CH2, IN_DONE_CH2_INT_ENA, 0, 1) + +REG32(DMA_INT_CLR_CH2, 0x02C) + FIELD(DMA_INT_CLR_CH2, OUTFIFO_UDF_CH2_INT_CLR, 12, 1) + FIELD(DMA_INT_CLR_CH2, OUTFIFO_OVF_CH2_INT_CLR, 11, 1) + FIELD(DMA_INT_CLR_CH2, INFIFO_UDF_CH2_INT_CLR, 10, 1) + FIELD(DMA_INT_CLR_CH2, INFIFO_OVF_CH2_INT_CLR, 9, 1) + FIELD(DMA_INT_CLR_CH2, OUT_TOTAL_EOF_CH2_INT_CLR, 8, 1) + FIELD(DMA_INT_CLR_CH2, IN_DSCR_EMPTY_CH2_INT_CLR, 7, 1) + FIELD(DMA_INT_CLR_CH2, OUT_DSCR_ERR_CH2_INT_CLR, 6, 1) + FIELD(DMA_INT_CLR_CH2, IN_DSCR_ERR_CH2_INT_CLR, 5, 1) + FIELD(DMA_INT_CLR_CH2, OUT_EOF_CH2_INT_CLR, 4, 1) + FIELD(DMA_INT_CLR_CH2, OUT_DONE_CH2_INT_CLR, 3, 1) + FIELD(DMA_INT_CLR_CH2, IN_ERR_EOF_CH2_INT_CLR, 2, 1) + FIELD(DMA_INT_CLR_CH2, IN_SUC_EOF_CH2_INT_CLR, 1, 1) + FIELD(DMA_INT_CLR_CH2, IN_DONE_CH2_INT_CLR, 0, 1) + +REG32(DMA_AHB_TEST, 0x040) + FIELD(DMA_AHB_TEST, AHB_TESTADDR, 4, 2) + FIELD(DMA_AHB_TEST, AHB_TESTMODE, 0, 3) + +REG32(DMA_MISC_CONF, 0x044) + FIELD(DMA_MISC_CONF, CLK_EN, 3, 1) + FIELD(DMA_MISC_CONF, ARB_PRI_DIS, 2, 1) + FIELD(DMA_MISC_CONF, AHBM_RST_INTER, 0, 1) + +REG32(DMA_DATE, 0x048) + FIELD(DMA_DATE, DATE, 0, 32) + +REG32(DMA_IN_CONF0_CH0, 0x070) + FIELD(DMA_IN_CONF0_CH0, MEM_TRANS_EN_CH0, 4, 1) + FIELD(DMA_IN_CONF0_CH0, IN_DATA_BURST_EN_CH0, 3, 1) + FIELD(DMA_IN_CONF0_CH0, INDSCR_BURST_EN_CH0, 2, 1) + FIELD(DMA_IN_CONF0_CH0, IN_LOOP_TEST_CH0, 1, 1) + FIELD(DMA_IN_CONF0_CH0, IN_RST_CH0, 0, 1) + +REG32(DMA_IN_CONF1_CH0, 0x074) + FIELD(DMA_IN_CONF1_CH0, IN_CHECK_OWNER_CH0, 12, 1) + +REG32(DMA_INFIFO_STATUS_CH0, 0x078) + FIELD(DMA_INFIFO_STATUS_CH0, IN_BUF_HUNGRY_CH0, 27, 1) + FIELD(DMA_INFIFO_STATUS_CH0, IN_REMAIN_UNDER_4B_CH0, 26, 1) + FIELD(DMA_INFIFO_STATUS_CH0, IN_REMAIN_UNDER_3B_CH0, 25, 1) + FIELD(DMA_INFIFO_STATUS_CH0, IN_REMAIN_UNDER_2B_CH0, 24, 1) + FIELD(DMA_INFIFO_STATUS_CH0, IN_REMAIN_UNDER_1B_CH0, 23, 1) + FIELD(DMA_INFIFO_STATUS_CH0, INFIFO_CNT_CH0, 2, 6) + FIELD(DMA_INFIFO_STATUS_CH0, INFIFO_EMPTY_CH0, 1, 1) + FIELD(DMA_INFIFO_STATUS_CH0, INFIFO_FULL_CH0, 0, 1) + +REG32(DMA_IN_POP_CH0, 0x07C) + FIELD(DMA_IN_POP_CH0, INFIFO_POP_CH0, 12, 1) + FIELD(DMA_IN_POP_CH0, INFIFO_RDATA_CH0, 0, 12) + +REG32(DMA_IN_LINK_CH0, 0x080) + FIELD(DMA_IN_LINK_CH0, INLINK_PARK_CH0, 24, 1) + FIELD(DMA_IN_LINK_CH0, INLINK_RESTART_CH0, 23, 1) + FIELD(DMA_IN_LINK_CH0, INLINK_START_CH0, 22, 1) + FIELD(DMA_IN_LINK_CH0, INLINK_STOP_CH0, 21, 1) + FIELD(DMA_IN_LINK_CH0, INLINK_AUTO_RET_CH0, 20, 1) + FIELD(DMA_IN_LINK_CH0, INLINK_ADDR_CH0, 0, 20) + +REG32(DMA_IN_STATE_CH0, 0x084) + FIELD(DMA_IN_STATE_CH0, IN_STATE_CH0, 20, 3) + FIELD(DMA_IN_STATE_CH0, IN_DSCR_STATE_CH0, 18, 2) + FIELD(DMA_IN_STATE_CH0, INLINK_DSCR_ADDR_CH0, 0, 18) + +REG32(DMA_IN_SUC_EOF_DES_ADDR_CH0, 0x088) + FIELD(DMA_IN_SUC_EOF_DES_ADDR_CH0, IN_SUC_EOF_DES_ADDR_CH0, 0, 32) + +REG32(DMA_IN_ERR_EOF_DES_ADDR_CH0, 0x08C) + FIELD(DMA_IN_ERR_EOF_DES_ADDR_CH0, IN_ERR_EOF_DES_ADDR_CH0, 0, 32) + +REG32(DMA_IN_DSCR_CH0, 0x090) + FIELD(DMA_IN_DSCR_CH0, INLINK_DSCR_CH0, 0, 32) + +REG32(DMA_IN_DSCR_BF0_CH0, 0x094) + FIELD(DMA_IN_DSCR_BF0_CH0, INLINK_DSCR_BF0_CH0, 0, 32) + +REG32(DMA_IN_DSCR_BF1_CH0, 0x098) + FIELD(DMA_IN_DSCR_BF1_CH0, INLINK_DSCR_BF1_CH0, 0, 32) + +REG32(DMA_IN_PRI_CH0, 0x09C) + FIELD(DMA_IN_PRI_CH0, RX_PRI_CH0, 0, 4) + +REG32(DMA_IN_PERI_SEL_CH0, 0x0A0) + FIELD(DMA_IN_PERI_SEL_CH0, PERI_IN_SEL_CH0, 0, 6) + +REG32(DMA_OUT_CONF0_CH0, 0x0D0) + FIELD(DMA_OUT_CONF0_CH0, OUT_DATA_BURST_EN_CH0, 5, 1) + FIELD(DMA_OUT_CONF0_CH0, OUTDSCR_BURST_EN_CH0, 4, 1) + FIELD(DMA_OUT_CONF0_CH0, OUT_EOF_MODE_CH0, 3, 1) + FIELD(DMA_OUT_CONF0_CH0, OUT_AUTO_WRBACK_CH0, 2, 1) + FIELD(DMA_OUT_CONF0_CH0, OUT_LOOP_TEST_CH0, 1, 1) + FIELD(DMA_OUT_CONF0_CH0, OUT_RST_CH0, 0, 1) + +REG32(DMA_OUT_CONF1_CH0, 0x0D4) + FIELD(DMA_OUT_CONF1_CH0, OUT_CHECK_OWNER_CH0, 12, 1) + +REG32(DMA_OUTFIFO_STATUS_CH0, 0x0D8) + FIELD(DMA_OUTFIFO_STATUS_CH0, OUT_REMAIN_UNDER_4B_CH0, 26, 1) + FIELD(DMA_OUTFIFO_STATUS_CH0, OUT_REMAIN_UNDER_3B_CH0, 25, 1) + FIELD(DMA_OUTFIFO_STATUS_CH0, OUT_REMAIN_UNDER_2B_CH0, 24, 1) + FIELD(DMA_OUTFIFO_STATUS_CH0, OUT_REMAIN_UNDER_1B_CH0, 23, 1) + FIELD(DMA_OUTFIFO_STATUS_CH0, OUTFIFO_CNT_CH0, 2, 6) + FIELD(DMA_OUTFIFO_STATUS_CH0, OUTFIFO_EMPTY_CH0, 1, 1) + FIELD(DMA_OUTFIFO_STATUS_CH0, OUTFIFO_FULL_CH0, 0, 1) + +REG32(DMA_OUT_PUSH_CH0, 0x0DC) + FIELD(DMA_OUT_PUSH_CH0, OUTFIFO_PUSH_CH0, 9, 1) + FIELD(DMA_OUT_PUSH_CH0, OUTFIFO_WDATA_CH0, 0, 9) + +REG32(DMA_OUT_LINK_CH0, 0x0E0) + FIELD(DMA_OUT_LINK_CH0, OUTLINK_PARK_CH0, 23, 1) + FIELD(DMA_OUT_LINK_CH0, OUTLINK_RESTART_CH0, 22, 1) + FIELD(DMA_OUT_LINK_CH0, OUTLINK_START_CH0, 21, 1) + FIELD(DMA_OUT_LINK_CH0, OUTLINK_STOP_CH0, 20, 1) + FIELD(DMA_OUT_LINK_CH0, OUTLINK_ADDR_CH0, 0, 20) + +REG32(DMA_OUT_STATE_CH0, 0x0E4) + FIELD(DMA_OUT_STATE_CH0, OUT_STATE_CH0, 20, 3) + FIELD(DMA_OUT_STATE_CH0, OUT_DSCR_STATE_CH0, 18, 2) + FIELD(DMA_OUT_STATE_CH0, OUTLINK_DSCR_ADDR_CH0, 0, 18) + +REG32(DMA_OUT_EOF_DES_ADDR_CH0, 0x0E8) + FIELD(DMA_OUT_EOF_DES_ADDR_CH0, OUT_EOF_DES_ADDR_CH0, 0, 32) + +REG32(DMA_OUT_EOF_BFR_DES_ADDR_CH0, 0x0EC) + FIELD(DMA_OUT_EOF_BFR_DES_ADDR_CH0, OUT_EOF_BFR_DES_ADDR_CH0, 0, 32) + +REG32(DMA_OUT_DSCR_CH0, 0x0F0) + FIELD(DMA_OUT_DSCR_CH0, OUTLINK_DSCR_CH0, 0, 32) + +REG32(DMA_OUT_DSCR_BF0_CH0, 0x0F4) + FIELD(DMA_OUT_DSCR_BF0_CH0, OUTLINK_DSCR_BF0_CH0, 0, 32) + +REG32(DMA_OUT_DSCR_BF1_CH0, 0x0F8) + FIELD(DMA_OUT_DSCR_BF1_CH0, OUTLINK_DSCR_BF1_CH0, 0, 32) + +REG32(DMA_OUT_PRI_CH0, 0x0FC) + FIELD(DMA_OUT_PRI_CH0, TX_PRI_CH0, 0, 4) + +REG32(DMA_OUT_PERI_SEL_CH0, 0x100) + FIELD(DMA_OUT_PERI_SEL_CH0, PERI_OUT_SEL_CH0, 0, 6) + +REG32(DMA_IN_CONF0_CH1, 0x130) + FIELD(DMA_IN_CONF0_CH1, MEM_TRANS_EN_CH1, 4, 1) + FIELD(DMA_IN_CONF0_CH1, IN_DATA_BURST_EN_CH1, 3, 1) + FIELD(DMA_IN_CONF0_CH1, INDSCR_BURST_EN_CH1, 2, 1) + FIELD(DMA_IN_CONF0_CH1, IN_LOOP_TEST_CH1, 1, 1) + FIELD(DMA_IN_CONF0_CH1, IN_RST_CH1, 0, 1) + +REG32(DMA_IN_CONF1_CH1, 0x134) + FIELD(DMA_IN_CONF1_CH1, IN_CHECK_OWNER_CH1, 12, 1) + +REG32(DMA_INFIFO_STATUS_CH1, 0x138) + FIELD(DMA_INFIFO_STATUS_CH1, IN_BUF_HUNGRY_CH1, 27, 1) + FIELD(DMA_INFIFO_STATUS_CH1, IN_REMAIN_UNDER_4B_CH1, 26, 1) + FIELD(DMA_INFIFO_STATUS_CH1, IN_REMAIN_UNDER_3B_CH1, 25, 1) + FIELD(DMA_INFIFO_STATUS_CH1, IN_REMAIN_UNDER_2B_CH1, 24, 1) + FIELD(DMA_INFIFO_STATUS_CH1, IN_REMAIN_UNDER_1B_CH1, 23, 1) + FIELD(DMA_INFIFO_STATUS_CH1, INFIFO_CNT_CH1, 2, 6) + FIELD(DMA_INFIFO_STATUS_CH1, INFIFO_EMPTY_CH1, 1, 1) + FIELD(DMA_INFIFO_STATUS_CH1, INFIFO_FULL_CH1, 0, 1) + +REG32(DMA_IN_POP_CH1, 0x13C) + FIELD(DMA_IN_POP_CH1, INFIFO_POP_CH1, 12, 1) + FIELD(DMA_IN_POP_CH1, INFIFO_RDATA_CH1, 0, 12) + +REG32(DMA_IN_LINK_CH1, 0x140) + FIELD(DMA_IN_LINK_CH1, INLINK_PARK_CH1, 24, 1) + FIELD(DMA_IN_LINK_CH1, INLINK_RESTART_CH1, 23, 1) + FIELD(DMA_IN_LINK_CH1, INLINK_START_CH1, 22, 1) + FIELD(DMA_IN_LINK_CH1, INLINK_STOP_CH1, 21, 1) + FIELD(DMA_IN_LINK_CH1, INLINK_AUTO_RET_CH1, 20, 1) + FIELD(DMA_IN_LINK_CH1, INLINK_ADDR_CH1, 0, 20) + +REG32(DMA_IN_STATE_CH1, 0x144) + FIELD(DMA_IN_STATE_CH1, IN_STATE_CH1, 20, 3) + FIELD(DMA_IN_STATE_CH1, IN_DSCR_STATE_CH1, 18, 2) + FIELD(DMA_IN_STATE_CH1, INLINK_DSCR_ADDR_CH1, 0, 18) + +REG32(DMA_IN_SUC_EOF_DES_ADDR_CH1, 0x148) + FIELD(DMA_IN_SUC_EOF_DES_ADDR_CH1, IN_SUC_EOF_DES_ADDR_CH1, 0, 32) + +REG32(DMA_IN_ERR_EOF_DES_ADDR_CH1, 0x14C) + FIELD(DMA_IN_ERR_EOF_DES_ADDR_CH1, IN_ERR_EOF_DES_ADDR_CH1, 0, 32) + +REG32(DMA_IN_DSCR_CH1, 0x150) + FIELD(DMA_IN_DSCR_CH1, INLINK_DSCR_CH1, 0, 32) + +REG32(DMA_IN_DSCR_BF0_CH1, 0x154) + FIELD(DMA_IN_DSCR_BF0_CH1, INLINK_DSCR_BF0_CH1, 0, 32) + +REG32(DMA_IN_DSCR_BF1_CH1, 0x158) + FIELD(DMA_IN_DSCR_BF1_CH1, INLINK_DSCR_BF1_CH1, 0, 32) + +REG32(DMA_IN_PRI_CH1, 0x15C) + FIELD(DMA_IN_PRI_CH1, RX_PRI_CH1, 0, 4) + +REG32(DMA_IN_PERI_SEL_CH1, 0x160) + FIELD(DMA_IN_PERI_SEL_CH1, PERI_IN_SEL_CH1, 0, 6) + +REG32(DMA_OUT_CONF0_CH1, 0x190) + FIELD(DMA_OUT_CONF0_CH1, OUT_DATA_BURST_EN_CH1, 5, 1) + FIELD(DMA_OUT_CONF0_CH1, OUTDSCR_BURST_EN_CH1, 4, 1) + FIELD(DMA_OUT_CONF0_CH1, OUT_EOF_MODE_CH1, 3, 1) + FIELD(DMA_OUT_CONF0_CH1, OUT_AUTO_WRBACK_CH1, 2, 1) + FIELD(DMA_OUT_CONF0_CH1, OUT_LOOP_TEST_CH1, 1, 1) + FIELD(DMA_OUT_CONF0_CH1, OUT_RST_CH1, 0, 1) + +REG32(DMA_OUT_CONF1_CH1, 0x194) + FIELD(DMA_OUT_CONF1_CH1, OUT_CHECK_OWNER_CH1, 12, 1) + +REG32(DMA_OUTFIFO_STATUS_CH1, 0x198) + FIELD(DMA_OUTFIFO_STATUS_CH1, OUT_REMAIN_UNDER_4B_CH1, 26, 1) + FIELD(DMA_OUTFIFO_STATUS_CH1, OUT_REMAIN_UNDER_3B_CH1, 25, 1) + FIELD(DMA_OUTFIFO_STATUS_CH1, OUT_REMAIN_UNDER_2B_CH1, 24, 1) + FIELD(DMA_OUTFIFO_STATUS_CH1, OUT_REMAIN_UNDER_1B_CH1, 23, 1) + FIELD(DMA_OUTFIFO_STATUS_CH1, OUTFIFO_CNT_CH1, 2, 6) + FIELD(DMA_OUTFIFO_STATUS_CH1, OUTFIFO_EMPTY_CH1, 1, 1) + FIELD(DMA_OUTFIFO_STATUS_CH1, OUTFIFO_FULL_CH1, 0, 1) + +REG32(DMA_OUT_PUSH_CH1, 0x19C) + FIELD(DMA_OUT_PUSH_CH1, OUTFIFO_PUSH_CH1, 9, 1) + FIELD(DMA_OUT_PUSH_CH1, OUTFIFO_WDATA_CH1, 0, 9) + +REG32(DMA_OUT_LINK_CH1, 0x1A0) + FIELD(DMA_OUT_LINK_CH1, OUTLINK_PARK_CH1, 23, 1) + FIELD(DMA_OUT_LINK_CH1, OUTLINK_RESTART_CH1, 22, 1) + FIELD(DMA_OUT_LINK_CH1, OUTLINK_START_CH1, 21, 1) + FIELD(DMA_OUT_LINK_CH1, OUTLINK_STOP_CH1, 20, 1) + FIELD(DMA_OUT_LINK_CH1, OUTLINK_ADDR_CH1, 0, 20) + +REG32(DMA_OUT_STATE_CH1, 0x1A4) + FIELD(DMA_OUT_STATE_CH1, OUT_STATE_CH1, 20, 3) + FIELD(DMA_OUT_STATE_CH1, OUT_DSCR_STATE_CH1, 18, 2) + FIELD(DMA_OUT_STATE_CH1, OUTLINK_DSCR_ADDR_CH1, 0, 18) + +REG32(DMA_OUT_EOF_DES_ADDR_CH1, 0x1A8) + FIELD(DMA_OUT_EOF_DES_ADDR_CH1, OUT_EOF_DES_ADDR_CH1, 0, 32) + +REG32(DMA_OUT_EOF_BFR_DES_ADDR_CH1, 0x1AC) + FIELD(DMA_OUT_EOF_BFR_DES_ADDR_CH1, OUT_EOF_BFR_DES_ADDR_CH1, 0, 32) + +REG32(DMA_OUT_DSCR_CH1, 0x1B0) + FIELD(DMA_OUT_DSCR_CH1, OUTLINK_DSCR_CH1, 0, 32) + +REG32(DMA_OUT_DSCR_BF0_CH1, 0x1B4) + FIELD(DMA_OUT_DSCR_BF0_CH1, OUTLINK_DSCR_BF0_CH1, 0, 32) + +REG32(DMA_OUT_DSCR_BF1_CH1, 0x1B8) + FIELD(DMA_OUT_DSCR_BF1_CH1, OUTLINK_DSCR_BF1_CH1, 0, 32) + +REG32(DMA_OUT_PRI_CH1, 0x1BC) + FIELD(DMA_OUT_PRI_CH1, TX_PRI_CH1, 0, 4) + +REG32(DMA_OUT_PERI_SEL_CH1, 0x1C0) + FIELD(DMA_OUT_PERI_SEL_CH1, PERI_OUT_SEL_CH1, 0, 6) + +REG32(DMA_IN_CONF0_CH2, 0x1F0) + FIELD(DMA_IN_CONF0_CH2, MEM_TRANS_EN_CH2, 4, 1) + FIELD(DMA_IN_CONF0_CH2, IN_DATA_BURST_EN_CH2, 3, 1) + FIELD(DMA_IN_CONF0_CH2, INDSCR_BURST_EN_CH2, 2, 1) + FIELD(DMA_IN_CONF0_CH2, IN_LOOP_TEST_CH2, 1, 1) + FIELD(DMA_IN_CONF0_CH2, IN_RST_CH2, 0, 1) + +REG32(DMA_IN_CONF1_CH2, 0x1F4) + FIELD(DMA_IN_CONF1_CH2, IN_CHECK_OWNER_CH2, 12, 1) + +REG32(DMA_INFIFO_STATUS_CH2, 0x1F8) + FIELD(DMA_INFIFO_STATUS_CH2, IN_BUF_HUNGRY_CH2, 27, 1) + FIELD(DMA_INFIFO_STATUS_CH2, IN_REMAIN_UNDER_4B_CH2, 26, 1) + FIELD(DMA_INFIFO_STATUS_CH2, IN_REMAIN_UNDER_3B_CH2, 25, 1) + FIELD(DMA_INFIFO_STATUS_CH2, IN_REMAIN_UNDER_2B_CH2, 24, 1) + FIELD(DMA_INFIFO_STATUS_CH2, IN_REMAIN_UNDER_1B_CH2, 23, 1) + FIELD(DMA_INFIFO_STATUS_CH2, INFIFO_CNT_CH2, 2, 6) + FIELD(DMA_INFIFO_STATUS_CH2, INFIFO_EMPTY_CH2, 1, 1) + FIELD(DMA_INFIFO_STATUS_CH2, INFIFO_FULL_CH2, 0, 1) + +REG32(DMA_IN_POP_CH2, 0x1FC) + FIELD(DMA_IN_POP_CH2, INFIFO_POP_CH2, 12, 1) + FIELD(DMA_IN_POP_CH2, INFIFO_RDATA_CH2, 0, 12) + +REG32(DMA_IN_LINK_CH2, 0x200) + FIELD(DMA_IN_LINK_CH2, INLINK_PARK_CH2, 24, 1) + FIELD(DMA_IN_LINK_CH2, INLINK_RESTART_CH2, 23, 1) + FIELD(DMA_IN_LINK_CH2, INLINK_START_CH2, 22, 1) + FIELD(DMA_IN_LINK_CH2, INLINK_STOP_CH2, 21, 1) + FIELD(DMA_IN_LINK_CH2, INLINK_AUTO_RET_CH2, 20, 1) + FIELD(DMA_IN_LINK_CH2, INLINK_ADDR_CH2, 0, 20) + +REG32(DMA_IN_STATE_CH2, 0x204) + FIELD(DMA_IN_STATE_CH2, IN_STATE_CH2, 20, 3) + FIELD(DMA_IN_STATE_CH2, IN_DSCR_STATE_CH2, 18, 2) + FIELD(DMA_IN_STATE_CH2, INLINK_DSCR_ADDR_CH2, 0, 18) + +REG32(DMA_IN_SUC_EOF_DES_ADDR_CH2, 0x208) + FIELD(DMA_IN_SUC_EOF_DES_ADDR_CH2, IN_SUC_EOF_DES_ADDR_CH2, 0, 32) + +REG32(DMA_IN_ERR_EOF_DES_ADDR_CH2, 0x20C) + FIELD(DMA_IN_ERR_EOF_DES_ADDR_CH2, IN_ERR_EOF_DES_ADDR_CH2, 0, 32) + +REG32(DMA_IN_DSCR_CH2, 0x210) + FIELD(DMA_IN_DSCR_CH2, INLINK_DSCR_CH2, 0, 32) + +REG32(DMA_IN_DSCR_BF0_CH2, 0x214) + FIELD(DMA_IN_DSCR_BF0_CH2, INLINK_DSCR_BF0_CH2, 0, 32) + +REG32(DMA_IN_DSCR_BF1_CH2, 0x218) + FIELD(DMA_IN_DSCR_BF1_CH2, INLINK_DSCR_BF1_CH2, 0, 32) + +REG32(DMA_IN_PRI_CH2, 0x21C) + FIELD(DMA_IN_PRI_CH2, RX_PRI_CH2, 0, 4) + +REG32(DMA_IN_PERI_SEL_CH2, 0x220) + FIELD(DMA_IN_PERI_SEL_CH2, PERI_IN_SEL_CH2, 0, 6) + +REG32(DMA_OUT_CONF0_CH2, 0x250) + FIELD(DMA_OUT_CONF0_CH2, OUT_DATA_BURST_EN_CH2, 5, 1) + FIELD(DMA_OUT_CONF0_CH2, OUTDSCR_BURST_EN_CH2, 4, 1) + FIELD(DMA_OUT_CONF0_CH2, OUT_EOF_MODE_CH2, 3, 1) + FIELD(DMA_OUT_CONF0_CH2, OUT_AUTO_WRBACK_CH2, 2, 1) + FIELD(DMA_OUT_CONF0_CH2, OUT_LOOP_TEST_CH2, 1, 1) + FIELD(DMA_OUT_CONF0_CH2, OUT_RST_CH2, 0, 1) + +REG32(DMA_OUT_CONF1_CH2, 0x254) + FIELD(DMA_OUT_CONF1_CH2, OUT_CHECK_OWNER_CH2, 12, 1) + +REG32(DMA_OUTFIFO_STATUS_CH2, 0x258) + FIELD(DMA_OUTFIFO_STATUS_CH2, OUT_REMAIN_UNDER_4B_CH2, 26, 1) + FIELD(DMA_OUTFIFO_STATUS_CH2, OUT_REMAIN_UNDER_3B_CH2, 25, 1) + FIELD(DMA_OUTFIFO_STATUS_CH2, OUT_REMAIN_UNDER_2B_CH2, 24, 1) + FIELD(DMA_OUTFIFO_STATUS_CH2, OUT_REMAIN_UNDER_1B_CH2, 23, 1) + FIELD(DMA_OUTFIFO_STATUS_CH2, OUTFIFO_CNT_CH2, 2, 6) + FIELD(DMA_OUTFIFO_STATUS_CH2, OUTFIFO_EMPTY_CH2, 1, 1) + FIELD(DMA_OUTFIFO_STATUS_CH2, OUTFIFO_FULL_CH2, 0, 1) + +REG32(DMA_OUT_PUSH_CH2, 0x25C) + FIELD(DMA_OUT_PUSH_CH2, OUTFIFO_PUSH_CH2, 9, 1) + FIELD(DMA_OUT_PUSH_CH2, OUTFIFO_WDATA_CH2, 0, 9) + +REG32(DMA_OUT_LINK_CH2, 0x260) + FIELD(DMA_OUT_LINK_CH2, OUTLINK_PARK_CH2, 23, 1) + FIELD(DMA_OUT_LINK_CH2, OUTLINK_RESTART_CH2, 22, 1) + FIELD(DMA_OUT_LINK_CH2, OUTLINK_START_CH2, 21, 1) + FIELD(DMA_OUT_LINK_CH2, OUTLINK_STOP_CH2, 20, 1) + FIELD(DMA_OUT_LINK_CH2, OUTLINK_ADDR_CH2, 0, 20) + +REG32(DMA_OUT_STATE_CH2, 0x264) + FIELD(DMA_OUT_STATE_CH2, OUT_STATE_CH2, 20, 3) + FIELD(DMA_OUT_STATE_CH2, OUT_DSCR_STATE_CH2, 18, 2) + FIELD(DMA_OUT_STATE_CH2, OUTLINK_DSCR_ADDR_CH2, 0, 18) + +REG32(DMA_OUT_EOF_DES_ADDR_CH2, 0x268) + FIELD(DMA_OUT_EOF_DES_ADDR_CH2, OUT_EOF_DES_ADDR_CH2, 0, 32) + +REG32(DMA_OUT_EOF_BFR_DES_ADDR_CH2, 0x26C) + FIELD(DMA_OUT_EOF_BFR_DES_ADDR_CH2, OUT_EOF_BFR_DES_ADDR_CH2, 0, 32) + +REG32(DMA_OUT_DSCR_CH2, 0x270) + FIELD(DMA_OUT_DSCR_CH2, OUTLINK_DSCR_CH2, 0, 32) + +REG32(DMA_OUT_DSCR_BF0_CH2, 0x274) + FIELD(DMA_OUT_DSCR_BF0_CH2, OUTLINK_DSCR_BF0_CH2, 0, 32) + +REG32(DMA_OUT_DSCR_BF1_CH2, 0x278) + FIELD(DMA_OUT_DSCR_BF1_CH2, OUTLINK_DSCR_BF1_CH2, 0, 32) + +REG32(DMA_OUT_PRI_CH2, 0x27C) + FIELD(DMA_OUT_PRI_CH2, TX_PRI_CH2, 0, 4) + +REG32(DMA_OUT_PERI_SEL_CH2, 0x280) + FIELD(DMA_OUT_PERI_SEL_CH2, PERI_OUT_SEL_CH2, 0, 6) diff --git a/include/hw/gpio/esp32_gpio.h b/include/hw/gpio/esp32_gpio.h new file mode 100644 index 000000000000..163b41aa6b5a --- /dev/null +++ b/include/hw/gpio/esp32_gpio.h @@ -0,0 +1,27 @@ +#pragma once + +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/registerfields.h" + +#define TYPE_ESP32_GPIO "esp32.gpio" +#define ESP32_GPIO(obj) OBJECT_CHECK(Esp32GpioState, (obj), TYPE_ESP32_GPIO) +#define ESP32_GPIO_GET_CLASS(obj) OBJECT_GET_CLASS(Esp32GpioClass, obj, TYPE_ESP32_GPIO) +#define ESP32_GPIO_CLASS(klass) OBJECT_CLASS_CHECK(Esp32GpioClass, klass, TYPE_ESP32_GPIO) + +REG32(GPIO_STRAP, 0x0038) + +#define ESP32_STRAP_MODE_FLASH_BOOT 0x12 +#define ESP32_STRAP_MODE_UART_BOOT 0x0f + +typedef struct Esp32GpioState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + qemu_irq irq; + uint32_t strap_mode; +} Esp32GpioState; + +typedef struct Esp32GpioClass { + SysBusDeviceClass parent_class; +} Esp32GpioClass; diff --git a/include/hw/gpio/esp32c3_gpio.h b/include/hw/gpio/esp32c3_gpio.h new file mode 100644 index 000000000000..6fe8b72bd764 --- /dev/null +++ b/include/hw/gpio/esp32c3_gpio.h @@ -0,0 +1,24 @@ +#pragma once + +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "esp32_gpio.h" + +#define TYPE_ESP32C3_GPIO "esp32c3.gpio" +#define ESP32C3_GPIO(obj) OBJECT_CHECK(ESP32C3GPIOState, (obj), TYPE_ESP32C3_GPIO) +#define ESP32C3_GPIO_GET_CLASS(obj) OBJECT_GET_CLASS(ESP32C3GPIOClass, obj, TYPE_ESP32C3_GPIO) +#define ESP32C3_GPIO_CLASS(klass) OBJECT_CLASS_CHECK(ESP32C3GPIOClass, klass, TYPE_ESP32C3_GPIO) + +/* Bootstrap options for ESP32-C3 (4-bit) */ +#define ESP32C3_STRAP_MODE_FLASH_BOOT 0x8 /* SPI Boot */ +#define ESP32C3_STRAP_MODE_UART_BOOT 0x2 /* Diagnostic Mode0+UART0 download Mode */ +#define ESP32C3_STRAP_MODE_USB_BOOT 0x0 /* Diagnostic Mode1+USB download Mode */ + +typedef struct ESP32C3State { + Esp32GpioState parent; +} ESP32C3GPIOState; + +typedef struct ESP32C3GPIOClass { + Esp32GpioClass parent; +} ESP32C3GPIOClass; diff --git a/include/hw/i2c/esp32_i2c.h b/include/hw/i2c/esp32_i2c.h new file mode 100644 index 000000000000..b17dc75c8de4 --- /dev/null +++ b/include/hw/i2c/esp32_i2c.h @@ -0,0 +1,109 @@ +#ifndef ESP32_I2C_H +#define ESP32_I2C_H + +#include "hw/sysbus.h" +#include "qemu/fifo8.h" +#include "hw/i2c/i2c.h" +#include "hw/registerfields.h" + +#define TYPE_ESP32_I2C "esp32.i2c" +#define Esp32_I2C(obj) OBJECT_CHECK(Esp32I2CState, (obj), TYPE_ESP32_I2C) + + +#define ESP32_I2C_MEM_SIZE 0x100 +#define ESP32_I2C_FIFO_LENGTH 32 +#define ESP32_I2C_CMD_COUNT 16 + + +typedef struct Esp32I2CState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + qemu_irq irq; + I2CBus *bus; + Fifo8 rx_fifo; + Fifo8 tx_fifo; + bool trans_ongoing; + + uint32_t ctr_reg; + uint32_t timeout_reg; + uint32_t int_ena_reg; + uint32_t int_raw_reg; + uint32_t sda_hold_reg; + uint32_t sda_sample_reg; + uint32_t high_period_reg; + uint32_t low_period_reg; + uint32_t start_hold_reg; + uint32_t rstart_setup_reg; + uint32_t stop_hold_reg; + uint32_t stop_setup_reg; + uint32_t cmd_reg[ESP32_I2C_CMD_COUNT]; +} Esp32I2CState; + + +REG32(I2C_CTR, 0x04); + FIELD(I2C_CTR, MS_MODE, 4, 1); + FIELD(I2C_CTR, TRANS_START, 5, 1); + +REG32(I2C_STATUS, 0x08); + FIELD(I2C_STATUS, BUS_BUSY, 4, 1); + FIELD(I2C_STATUS, RXFIFO_CNT, 8, 6); + FIELD(I2C_STATUS, TXFIFO_CNT, 18, 6); + +REG32(I2C_TIMEOUT, 0x0c); + +REG32(I2C_FIFO_CONF, 0x18); + FIELD(I2C_FIFO_CONF, NONFIFO_EN, 10, 1); + FIELD(I2C_FIFO_CONF, RX_FIFO_RST, 12, 1); + FIELD(I2C_FIFO_CONF, TX_FIFO_RST, 13, 1); + +REG32(I2C_FIFO_DATA, 0x1c); + +REG32(I2C_INT_RAW, 0x20); + FIELD(I2C_INT_RAW, ACK_ERR, 10, 1); + FIELD(I2C_INT_RAW, TRANS_COMPLETE, 7, 1); + FIELD(I2C_INT_RAW, END_DETECT, 3, 1); + +REG32(I2C_INT_CLR, 0x24); + FIELD(I2C_INT_CLR, ACK_ERR, 10, 1); + FIELD(I2C_INT_CLR, TRANS_COMPLETE, 7, 1); + FIELD(I2C_INT_CLR, END_DETECT, 3, 1); + +REG32(I2C_INT_ENA, 0x28); + FIELD(I2C_INT_ENA, ACK_ERR, 10, 1); + FIELD(I2C_INT_ENA, TRANS_COMPLETE, 7, 1); + FIELD(I2C_INT_ENA, END_DETECT, 3, 1); + +REG32(I2C_INT_ST, 0x2c); + FIELD(I2C_INT_ST, ACK_ERR, 10, 1); + FIELD(I2C_INT_ST, TRANS_COMPLETE, 7, 1); + FIELD(I2C_INT_ST, END_DETECT, 3, 1); + +REG32(I2C_SDA_HOLD, 0x30); +REG32(I2C_SDA_SAMPLE, 0x34); +REG32(I2C_HIGH_PERIOD, 0x38); +REG32(I2C_LOW_PERIOD, 0x00); // 0x00 is not a typo +REG32(I2C_START_HOLD, 0x40); +REG32(I2C_RSTART_SETUP, 0x44); +REG32(I2C_STOP_HOLD, 0x48); +REG32(I2C_STOP_SETUP, 0x4c); + +REG32(I2C_CMD, 0x58); + FIELD(I2C_CMD, BYTE_NUM, 0, 8); + FIELD(I2C_CMD, ACK_CHECK_EN, 8, 1); + FIELD(I2C_CMD, ACK_EXP, 9, 1); + FIELD(I2C_CMD, ACK_VAL, 10, 1); + FIELD(I2C_CMD, OPCODE, 11, 3); + FIELD(I2C_CMD, DONE, 31, 1); +/* 15 more command registers omitted */ + +/* I2C_CMD.OPCODE values */ +typedef enum { + I2C_OPCODE_RSTART = 0, + I2C_OPCODE_WRITE = 1, + I2C_OPCODE_READ = 2, + I2C_OPCODE_STOP = 3, + I2C_OPCODE_END = 4, +} i2c_opcode_t; + +#endif /* ESP32_I2C_H */ diff --git a/include/hw/misc/esp32_aes.h b/include/hw/misc/esp32_aes.h new file mode 100644 index 000000000000..76b8683e53b4 --- /dev/null +++ b/include/hw/misc/esp32_aes.h @@ -0,0 +1,46 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/esp32_reg.h" + +#define TYPE_ESP32_AES "misc.esp32.aes" +#define ESP32_AES(obj) OBJECT_CHECK(Esp32AesState, (obj), TYPE_ESP32_AES) + +#define ESP32_AES_TEXT_REG_CNT 4 +#define ESP32_AES_KEY_REG_CNT 8 + +#define ESP32_AES_ENCRYPTION_MODE TRUE +#define ESP32_AES_DECRYPTION_MODE FALSE + +typedef struct Esp32AesState { + SysBusDevice parent_object; + MemoryRegion iomem; + uint32_t text[ESP32_AES_TEXT_REG_CNT]; + uint32_t key[ESP32_AES_KEY_REG_CNT]; + uint32_t aes_idle_reg; + struct { + bool type; + int bits; + } mode; +} Esp32AesState; + +REG32(AES_START_REG, 0x00) +REG32(AES_IDLE_REG, 0x04) +REG32(AES_MODE_REG, 0x08) +REG32(AES_ENDIAN_REG, 0x40) + +REG32(AES_KEY_0_REG, 0x10) +REG32(AES_KEY_1_REG, 0x14) +REG32(AES_KEY_2_REG, 0x18) +REG32(AES_KEY_3_REG, 0x1C) +REG32(AES_KEY_4_REG, 0x20) +REG32(AES_KEY_5_REG, 0x24) +REG32(AES_KEY_6_REG, 0x28) +REG32(AES_KEY_7_REG, 0x2C) + +REG32(AES_TEXT_0_REG, 0x30) +REG32(AES_TEXT_1_REG, 0x34) +REG32(AES_TEXT_2_REG, 0x38) +REG32(AES_TEXT_3_REG, 0x3C) diff --git a/include/hw/misc/esp32_ana.h b/include/hw/misc/esp32_ana.h new file mode 100644 index 000000000000..8c4bc32c858f --- /dev/null +++ b/include/hw/misc/esp32_ana.h @@ -0,0 +1,17 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/esp32_reg.h" + + +#define TYPE_ESP32_ANA "misc.esp32.ana" +#define ESP32_ANA(obj) OBJECT_CHECK(Esp32AnaState, (obj), TYPE_ESP32_ANA) + +typedef struct Esp32AnaState { + SysBusDevice parent_obj; + MemoryRegion iomem; + uint32_t mem[1024]; +} Esp32AnaState; + diff --git a/include/hw/misc/esp32_crosscore_int.h b/include/hw/misc/esp32_crosscore_int.h new file mode 100644 index 000000000000..35c8739dda71 --- /dev/null +++ b/include/hw/misc/esp32_crosscore_int.h @@ -0,0 +1,17 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "hw/sysbus.h" +#include "sysemu/block-backend.h" + + +#define TYPE_ESP32_CROSSCORE_INT "misc.esp32.crosscoreint" +#define ESP32_CROSSCORE_INT(obj) OBJECT_CHECK(Esp32CrosscoreInt, (obj), TYPE_ESP32_CROSSCORE_INT) + +typedef struct Esp32CrosscoreInt { + SysBusDevice parent_obj; + MemoryRegion iomem; + int n_irqs; + qemu_irq *irqs; +} Esp32CrosscoreInt; diff --git a/include/hw/misc/esp32_dport.h b/include/hw/misc/esp32_dport.h new file mode 100644 index 000000000000..988c6ab36891 --- /dev/null +++ b/include/hw/misc/esp32_dport.h @@ -0,0 +1,178 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32_reg.h" +#include "sysemu/block-backend.h" +#include "hw/misc/esp32_flash_enc.h" + +typedef struct Esp32DportState Esp32DportState; +typedef struct Esp32CacheState Esp32CacheState; + +#define TYPE_ESP32_DPORT "misc.esp32.dport" +#define ESP32_DPORT(obj) OBJECT_CHECK(Esp32DportState, (obj), TYPE_ESP32_DPORT) + +#define ESP32_CACHE_PAGE_SIZE 0x10000 +#define ESP32_CACHE_PAGES_PER_REGION 64 +#define ESP32_CACHE_REGION_SIZE (ESP32_CACHE_PAGE_SIZE * ESP32_CACHE_PAGES_PER_REGION) +#define ESP32_CACHE_MMU_INVALID_VAL 0x100 +#define ESP32_CACHE_MMU_ENTRY_CHANGED 0x200 /* not a hardware flag; used here to check if the page data needs to be updated */ +#define ESP32_CACHE_MAX_PHYS_PAGES 0x100 + +typedef enum Esp32CacheRegionType { + ESP32_DCACHE_FLASH, + ESP32_ICACHE_FLASH, + ESP32_DCACHE_PSRAM, +} Esp32CacheRegionType; + +typedef struct Esp32CacheRegionState { + Esp32CacheState* cache; + MemoryRegion mem; + MemoryRegion illegal_access_trap_mem; + Esp32CacheRegionType type; + hwaddr base; + uint32_t illegal_access_retval; + bool illegal_access_trap_en; + bool illegal_access_status; + uint16_t mmu_table[ESP32_CACHE_PAGES_PER_REGION]; +} Esp32CacheRegionState; + +typedef struct Esp32CacheState { + Esp32DportState* dport; + int core_id; + + uint32_t cache_ctrl_reg; + uint32_t cache_ctrl1_reg; + /* Using only the first 4MB range. + * TODO: add memory regions for other ports: iram1, irom0 + */ + Esp32CacheRegionState iram0; + Esp32CacheRegionState drom0; + Esp32CacheRegionState dram1; /* PSRAM */ +} Esp32CacheState; + +typedef struct Esp32DportState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + bool has_psram; + int cpu_count; + Esp32CacheState cache_state[ESP32_CPU_COUNT]; + BlockBackend *flash_blk; + qemu_irq appcpu_stall_req; + qemu_irq appcpu_reset_req; + qemu_irq clk_update_req; + qemu_irq cache_ill_irq; + qemu_irq flash_enc_en_gpio; + qemu_irq flash_dec_en_gpio; + + bool appcpu_reset_state; + bool appcpu_stall_state; + bool appcpu_clkgate_state; + uint32_t appcpu_boot_addr; + uint32_t cpuperiod_sel; + uint32_t cache_ill_trap_en_reg; + uint32_t slave_spi_config_reg; + +} Esp32DportState; + +void esp32_dport_clear_ill_trap_state(Esp32DportState* s); + +#define ESP32_DPORT_APPCPU_STALL_GPIO "appcpu-stall" +#define ESP32_DPORT_APPCPU_RESET_GPIO "appcpu-reset" +#define ESP32_DPORT_CLK_UPDATE_GPIO "clk-update" +#define ESP32_DPORT_CACHE_ILL_IRQ_GPIO "cache-ill-irq" +#define ESP32_DPORT_FLASH_ENC_EN_GPIO "flash-enc-en" +#define ESP32_DPORT_FLASH_DEC_EN_GPIO "flash-dec-en" + + +REG32(DPORT_APPCPU_RESET, 0x2c) +REG32(DPORT_APPCPU_CLK, 0x30) +REG32(DPORT_APPCPU_RUNSTALL, 0x34) +REG32(DPORT_APPCPU_BOOT_ADDR, 0x38) + +REG32(DPORT_CPU_PER_CONF, 0x3c) + FIELD(DPORT_CPU_PER_CONF, CPUPERIOD_SEL, 0, 2) + +REG32(DPORT_PRO_CACHE_CTRL, 0x40) + FIELD(DPORT_PRO_CACHE_CTRL, CACHE_FLUSH_DONE, 5, 1) + FIELD(DPORT_PRO_CACHE_CTRL, CACHE_FLUSH_ENA, 4, 1) + FIELD(DPORT_PRO_CACHE_CTRL, CACHE_ENA, 3, 1) + +REG32(DPORT_PRO_CACHE_CTRL1, 0x44) + FIELD(DPORT_PRO_CACHE_CTRL1, MMU_IA_CLR, 13, 1) + FIELD(DPORT_PRO_CACHE_CTRL1, MASK_OPSDRAM, 5, 1) + FIELD(DPORT_PRO_CACHE_CTRL1, MASK_DROM0, 4, 1) + FIELD(DPORT_PRO_CACHE_CTRL1, MASK_DRAM1, 3, 1) + FIELD(DPORT_PRO_CACHE_CTRL1, MASK_IROM0, 2, 1) + FIELD(DPORT_PRO_CACHE_CTRL1, MASK_IRAM1, 1, 1) + FIELD(DPORT_PRO_CACHE_CTRL1, MASK_IRAM0, 0, 1) + +REG32(DPORT_APP_CACHE_CTRL, 0x58) + FIELD(DPORT_APP_CACHE_CTRL, CACHE_FLUSH_DONE, 5, 1) + FIELD(DPORT_APP_CACHE_CTRL, CACHE_FLUSH_ENA, 4, 1) + FIELD(DPORT_APP_CACHE_CTRL, CACHE_ENA, 3, 1) + +REG32(DPORT_APP_CACHE_CTRL1, 0x5C) + FIELD(DPORT_APP_CACHE_CTRL1, MMU_IA_CLR, 13, 1) + FIELD(DPORT_APP_CACHE_CTRL1, MASK_OPSDRAM, 5, 1) + FIELD(DPORT_APP_CACHE_CTRL1, MASK_DROM0, 4, 1) + FIELD(DPORT_APP_CACHE_CTRL1, MASK_DRAM1, 3, 1) + FIELD(DPORT_APP_CACHE_CTRL1, MASK_IROM0, 2, 1) + FIELD(DPORT_APP_CACHE_CTRL1, MASK_IRAM1, 1, 1) + FIELD(DPORT_APP_CACHE_CTRL1, MASK_IRAM0, 0, 1) + +REG32(DPORT_SLAVE_SPI_CONFIG, 0xC8) + FIELD(DPORT_SLAVE_SPI_CONFIG, SLAVE_SPI_ENCRYPT_ENABLE, 8, 1) + FIELD(DPORT_SLAVE_SPI_CONFIG, SLAVE_SPI_DECRYPT_ENABLE, 12, 1) + +REG32(DPORT_CPU_INTR_FROM_CPU_0, 0xdc) +REG32(DPORT_CPU_INTR_FROM_CPU_1, 0xe0) +REG32(DPORT_CPU_INTR_FROM_CPU_2, 0xe4) +REG32(DPORT_CPU_INTR_FROM_CPU_3, 0xe8) + +REG32(DPORT_PRO_MAC_INTR_MAP, 0x104) +REG32(DPORT_APP_MAC_INTR_MAP, 0x218) + +REG32(DPORT_PRO_DCACHE_DBUG0, 0x3f0) + FIELD(DPORT_PRO_DCACHE_DBUG0, CACHE_STATE, 7, 12) + +REG32(DPORT_PRO_DCACHE_DBUG3, 0x3FC) + FIELD(DPORT_PRO_DCACHE_DBUG3, IA_INT_OPPOSITE, 9, 1) + FIELD(DPORT_PRO_DCACHE_DBUG3, IA_INT_DRAM1, 10, 1) + FIELD(DPORT_PRO_DCACHE_DBUG3, IA_INT_IROM0, 11, 1) + FIELD(DPORT_PRO_DCACHE_DBUG3, IA_INT_IRAM1, 12, 1) + FIELD(DPORT_PRO_DCACHE_DBUG3, IA_INT_IRAM0, 13, 1) + FIELD(DPORT_PRO_DCACHE_DBUG3, IA_INT_DROM0, 14, 1) + +REG32(DPORT_APP_DCACHE_DBUG0, 0x418) + FIELD(DPORT_APP_DCACHE_DBUG0, CACHE_STATE, 7, 12) + +REG32(DPORT_APP_DCACHE_DBUG3, 0x424) + FIELD(DPORT_APP_DCACHE_DBUG3, IA_INT_OPPOSITE, 9, 1) + FIELD(DPORT_APP_DCACHE_DBUG3, IA_INT_DRAM1, 10, 1) + FIELD(DPORT_APP_DCACHE_DBUG3, IA_INT_IROM0, 11, 1) + FIELD(DPORT_APP_DCACHE_DBUG3, IA_INT_IRAM1, 12, 1) + FIELD(DPORT_APP_DCACHE_DBUG3, IA_INT_IRAM0, 13, 1) + FIELD(DPORT_APP_DCACHE_DBUG3, IA_INT_DROM0, 14, 1) + +REG32(DPORT_CACHE_IA_INT_EN, 0x5A0) + FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_PRO_OPPOSITE, 19, 1) + FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_PRO_DRAM1, 18, 1) + FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_PRO_IROM0, 17, 1) + FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_PRO_IRAM1, 16, 1) + FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_PRO_IRAM0, 15, 1) + FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_PRO_DROM0, 14, 1) + FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_APP_OPPOSITE, 5, 1) + FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_APP_DRAM1, 4, 1) + FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_APP_IROM0, 3, 1) + FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_APP_IRAM1, 2, 1) + FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_APP_IRAM0, 1, 1) + FIELD(DPORT_CACHE_IA_INT_EN, IA_INT_APP_DROM0, 0, 1) + + +#define ESP32_DPORT_PRO_INTMATRIX_BASE A_DPORT_PRO_MAC_INTR_MAP +#define ESP32_DPORT_APP_INTMATRIX_BASE A_DPORT_APP_MAC_INTR_MAP +#define ESP32_DPORT_CROSSCORE_INT_BASE A_DPORT_CPU_INTR_FROM_CPU_0 + diff --git a/include/hw/misc/esp32_fe.h b/include/hw/misc/esp32_fe.h new file mode 100644 index 000000000000..fa6c9faf29cc --- /dev/null +++ b/include/hw/misc/esp32_fe.h @@ -0,0 +1,17 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32_reg.h" + + +#define TYPE_ESP32_FE "misc.esp32.fe" +#define ESP32_FE(obj) OBJECT_CHECK(Esp32FeState, (obj), TYPE_ESP32_FE) + +typedef struct Esp32FeState { + SysBusDevice parent_obj; + MemoryRegion iomem; + uint32_t mem[1024]; +} Esp32FeState; + + diff --git a/include/hw/misc/esp32_flash_enc.h b/include/hw/misc/esp32_flash_enc.h new file mode 100644 index 000000000000..70de1115f61c --- /dev/null +++ b/include/hw/misc/esp32_flash_enc.h @@ -0,0 +1,62 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" + +#define TYPE_ESP32_FLASH_ENCRYPTION "misc.esp32.flash_encryption" +#define ESP32_FLASH_ENCRYPTION(obj) OBJECT_CHECK(Esp32FlashEncryptionState, (obj), TYPE_ESP32_FLASH_ENCRYPTION) + +#define ESP32_FLASH_ENCRYPTION_DL_MODE_GPIO "dl-mode" +#define ESP32_FLASH_ENCRYPTION_ENC_EN_GPIO "flash-enc-enable" +#define ESP32_FLASH_ENCRYPTION_DEC_EN_GPIO "flash-dec-enable" +#define ESP32_FLASH_ENCRYPTION_EFUSE_UPDATE_GPIO "efuse-update" + +typedef struct Esp32FlashEncryptionState { + SysBusDevice parent_obj; + MemoryRegion iomem; + + uint32_t buffer_reg[8]; + uint32_t address_reg; + + bool encryption_done; + uint32_t encrypted_buffer[8]; + + bool dl_mode; + bool encrypt_enable_reg; /* mirrors DPORT_SPI_ENCRYPT_ENABLE state */ + bool decrypt_enable_reg; /* mirrors DPORT_SPI_DECRYPT_ENABLE state */ + bool efuse_encrypt_enabled; + bool dl_mode_enc_disabled; + bool dl_mode_dec_disabled; + uint32_t efuse_key[8]; + +} Esp32FlashEncryptionState; + +/* returns NULL unless there is exactly one device */ +static inline Esp32FlashEncryptionState *esp32_flash_encryption_find(void) +{ + Object *o = object_resolve_path_type("", TYPE_ESP32_FLASH_ENCRYPTION, NULL); + return o ? ESP32_FLASH_ENCRYPTION(o) : NULL; +} + +bool esp32_flash_encryption_enabled(struct Esp32FlashEncryptionState* s); +bool esp32_flash_decryption_enabled(struct Esp32FlashEncryptionState* s); +void esp32_flash_encryption_get_result(struct Esp32FlashEncryptionState* s, uint32_t* dst, size_t dst_words); +void esp32_flash_decrypt_inplace(struct Esp32FlashEncryptionState* s, size_t flash_addr, uint32_t* data, size_t words); + + +REG32(FLASH_ENCRYPTION_BUFFER_0, 0x00) +REG32(FLASH_ENCRYPTION_BUFFER_1, 0x04) +REG32(FLASH_ENCRYPTION_BUFFER_2, 0x08) +REG32(FLASH_ENCRYPTION_BUFFER_3, 0x0C) +REG32(FLASH_ENCRYPTION_BUFFER_4, 0x10) +REG32(FLASH_ENCRYPTION_BUFFER_5, 0x14) +REG32(FLASH_ENCRYPTION_BUFFER_6, 0x18) +REG32(FLASH_ENCRYPTION_BUFFER_7, 0x1C) +REG32(FLASH_ENCRYPTION_START, 0x20) + FIELD(FLASH_ENCRYPTION_START, START, 0, 1) + +REG32(FLASH_ENCRYPTION_ADDRESS, 0x24) + +REG32(FLASH_ENCRYPTION_DONE, 0x28) + FIELD(FLASH_ENCRYPTION_DONE, DONE, 0, 1) diff --git a/include/hw/misc/esp32_ledc.h b/include/hw/misc/esp32_ledc.h new file mode 100644 index 000000000000..fe7e4e1dd4fa --- /dev/null +++ b/include/hw/misc/esp32_ledc.h @@ -0,0 +1,66 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/esp32_reg.h" +#include "hw/misc/led.h" + +#define TYPE_ESP32_LEDC "misc.esp32.ledc" +#define ESP32_LEDC(obj) OBJECT_CHECK(Esp32LEDCState, (obj), TYPE_ESP32_LEDC) +#define ESP32_LEDC_TIMER_CNT 8 +#define ESP32_LEDC_CHANNEL_CNT 16 + +typedef struct Esp32LEDCState { + SysBusDevice parent_object; + MemoryRegion iomem; + uint32_t duty_res[ESP32_LEDC_TIMER_CNT]; + uint32_t timer_conf_reg[ESP32_LEDC_TIMER_CNT]; + uint32_t channel_conf0_reg[ESP32_LEDC_CHANNEL_CNT]; + LEDState led[ESP32_LEDC_CHANNEL_CNT]; +} Esp32LEDCState; + +REG32(LEDC_CONF_REG, 0x190) + +#define LEDC_REG_GROUP(name, base) \ + REG32(name ## _CONF0_REG, (base)) \ + REG32(name ## _CONF1_REG, ((base) + 0x00C)) \ + REG32(name ## _DUTY_REG, ((base) + 0x008)) \ + REG32(name ## _DUTY_R_REG, ((base) + 0x010)) + +#define LEDC_TIMER_REG_GROUP(name, base) \ + REG32(name ## _CONF_REG, (base)) \ + REG32(name ## _VALUE_REG, ((base) + 0x004)) + +LEDC_REG_GROUP(LEDC_HSCH0, 0x000) +LEDC_REG_GROUP(LEDC_HSCH1, 0x014) +LEDC_REG_GROUP(LEDC_HSCH2, 0x028) +LEDC_REG_GROUP(LEDC_HSCH3, 0x03C) +LEDC_REG_GROUP(LEDC_HSCH4, 0x050) +LEDC_REG_GROUP(LEDC_HSCH5, 0x064) +LEDC_REG_GROUP(LEDC_HSCH6, 0x078) +LEDC_REG_GROUP(LEDC_HSCH7, 0x08C) + +LEDC_REG_GROUP(LEDC_LSCH0, 0x0A0) +LEDC_REG_GROUP(LEDC_LSCH1, 0x0B4) +LEDC_REG_GROUP(LEDC_LSCH2, 0x0C8) +LEDC_REG_GROUP(LEDC_LSCH3, 0x0DC) +LEDC_REG_GROUP(LEDC_LSCH4, 0x0F0) +LEDC_REG_GROUP(LEDC_LSCH5, 0x104) +LEDC_REG_GROUP(LEDC_LSCH6, 0x118) +LEDC_REG_GROUP(LEDC_LSCH7, 0x12C) + +LEDC_TIMER_REG_GROUP(LEDC_HSTIMER0, 0x140) +LEDC_TIMER_REG_GROUP(LEDC_HSTIMER1, 0x148) +LEDC_TIMER_REG_GROUP(LEDC_HSTIMER2, 0x150) +LEDC_TIMER_REG_GROUP(LEDC_HSTIMER3, 0x158) + +LEDC_TIMER_REG_GROUP(LEDC_LSTIMER0, 0x160) +LEDC_TIMER_REG_GROUP(LEDC_LSTIMER1, 0x168) +LEDC_TIMER_REG_GROUP(LEDC_LSTIMER2, 0x170) +LEDC_TIMER_REG_GROUP(LEDC_LSTIMER3, 0x178) + +REG32(LEDC_INT_RAW_REG, 0x180) +REG32(LEDC_INT_ST_REG, 0x184) +REG32(LEDC_INT_ENA_REG, 0x188) +REG32(LEDC_INT_CLR_REG, 0x18C) diff --git a/include/hw/misc/esp32_phya.h b/include/hw/misc/esp32_phya.h new file mode 100644 index 000000000000..8a4c66b6d8b9 --- /dev/null +++ b/include/hw/misc/esp32_phya.h @@ -0,0 +1,17 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32_reg.h" + + +#define TYPE_ESP32_PHYA "misc.esp32.phya" +#define ESP32_PHYA(obj) OBJECT_CHECK(Esp32PhyaState, (obj), TYPE_ESP32_PHYA) + +typedef struct Esp32PhyaState { + SysBusDevice parent_obj; + MemoryRegion iomem; + uint32_t mem[1024]; +} Esp32PhyaState; + + diff --git a/include/hw/misc/esp32_reg.h b/include/hw/misc/esp32_reg.h new file mode 100644 index 000000000000..669a0c0419b0 --- /dev/null +++ b/include/hw/misc/esp32_reg.h @@ -0,0 +1,150 @@ +#pragma once + + +#define DR_REG_DPORT_BASE 0x3ff00000 +#define DR_REG_AES_BASE 0x3ff01000 +#define DR_REG_RSA_BASE 0x3ff02000 +#define DR_REG_SHA_BASE 0x3ff03000 +#define DR_REG_FLASH_MMU_TABLE_PRO 0x3ff10000 +#define DR_REG_FLASH_MMU_TABLE_APP 0x3ff12000 +#define DR_REG_DPORT_END 0x3ff13FFC +#define DR_REG_DPORT_APB_BASE 0x3ff40000 +#define DR_REG_UART_BASE 0x3ff40000 +#define DR_REG_SPI1_BASE 0x3ff42000 +#define DR_REG_SPI0_BASE 0x3ff43000 +#define DR_REG_GPIO_BASE 0x3ff44000 +#define DR_REG_GPIO_SD_BASE 0x3ff44f00 +#define DR_REG_FE2_BASE 0x3ff45000 +#define DR_REG_FE_BASE 0x3ff46000 +#define DR_REG_FRC_TIMER_BASE 0x3ff47000 +#define DR_REG_RTCCNTL_BASE 0x3ff48000 +#define DR_REG_RTCIO_BASE 0x3ff48400 +#define DR_REG_SENS_BASE 0x3ff48800 +#define DR_REG_RTC_I2C_BASE 0x3ff48C00 +#define DR_REG_IO_MUX_BASE 0x3ff49000 +#define DR_REG_HINF_BASE 0x3ff4B000 +#define DR_REG_UHCI1_BASE 0x3ff4C000 +#define DR_REG_ANA_BASE 0x3ff4E000 +#define DR_REG_I2S_BASE 0x3ff4F000 +#define DR_REG_UART1_BASE 0x3ff50000 +#define DR_REG_BT_BASE 0x3ff51000 +#define DR_REG_I2C_EXT_BASE 0x3ff53000 +#define DR_REG_UHCI0_BASE 0x3ff54000 +#define DR_REG_SLCHOST_BASE 0x3ff55000 +#define DR_REG_RMT_BASE 0x3ff56000 +#define DR_REG_PCNT_BASE 0x3ff57000 +#define DR_REG_SLC_BASE 0x3ff58000 +#define DR_REG_LEDC_BASE 0x3ff59000 +#define DR_REG_EFUSE_BASE 0x3ff5A000 +#define DR_REG_SPI_ENCRYPT_BASE 0x3ff5B000 +#define DR_REG_NRX_BASE 0x3ff5C000 +// ^ modified from official value of 0x3ff5CC00 +#define DR_REG_BB_BASE 0x3ff5D000 +#define DR_REG_PWM_BASE 0x3ff5E000 +#define DR_REG_TIMERGROUP0_BASE 0x3ff5F000 +#define DR_REG_TIMERGROUP1_BASE 0x3ff60000 +#define DR_REG_RTCMEM0_BASE 0x3ff61000 +#define DR_REG_RTCMEM1_BASE 0x3ff62000 +#define DR_REG_RTCMEM2_BASE 0x3ff63000 +#define DR_REG_SPI2_BASE 0x3ff64000 +#define DR_REG_SPI3_BASE 0x3ff65000 +#define DR_REG_SYSCON_BASE 0x3ff66000 +#define DR_REG_APB_CTRL_BASE 0x3ff66000 /* Old name for SYSCON, to be removed */ +#define DR_REG_I2C1_EXT_BASE 0x3ff67000 +#define DR_REG_SDMMC_BASE 0x3ff68000 +#define DR_REG_EMAC_BASE 0x3ff69000 +#define DR_REG_CAN_BASE 0x3ff6B000 +#define DR_REG_PWM1_BASE 0x3ff6C000 +#define DR_REG_I2S1_BASE 0x3ff6D000 +#define DR_REG_UART2_BASE 0x3ff6E000 +#define DR_REG_PWM2_BASE 0x3ff6F000 +#define DR_REG_PWM3_BASE 0x3ff70000 +#define DR_REG_PHY_BASE 0x3ff71000 +#define DR_REG_WIFI_BASE 0x3ff73000 +#define DR_REG_PHYA_BASE 0x3ff74000 +#define DR_REG_WDEV_BASE 0x3ff75000 + +#define APB_REG_BASE 0x60000000 + +#define ETS_WIFI_MAC_INTR_SOURCE 0/**< interrupt of WiFi MAC, level*/ +#define ETS_WIFI_MAC_NMI_SOURCE 1/**< interrupt of WiFi MAC, NMI, use if MAC have bug to fix in NMI*/ +#define ETS_WIFI_BB_INTR_SOURCE 2/**< interrupt of WiFi BB, level, we can do some calibartion*/ +#define ETS_BT_MAC_INTR_SOURCE 3/**< will be cancelled*/ +#define ETS_BT_BB_INTR_SOURCE 4/**< interrupt of BT BB, level*/ +#define ETS_BT_BB_NMI_SOURCE 5/**< interrupt of BT BB, NMI, use if BB have bug to fix in NMI*/ +#define ETS_RWBT_INTR_SOURCE 6/**< interrupt of RWBT, level*/ +#define ETS_RWBLE_INTR_SOURCE 7/**< interrupt of RWBLE, level*/ +#define ETS_RWBT_NMI_SOURCE 8/**< interrupt of RWBT, NMI, use if RWBT have bug to fix in NMI*/ +#define ETS_RWBLE_NMI_SOURCE 9/**< interrupt of RWBLE, NMI, use if RWBT have bug to fix in NMI*/ +#define ETS_SLC0_INTR_SOURCE 10/**< interrupt of SLC0, level*/ +#define ETS_SLC1_INTR_SOURCE 11/**< interrupt of SLC1, level*/ +#define ETS_UHCI0_INTR_SOURCE 12/**< interrupt of UHCI0, level*/ +#define ETS_UHCI1_INTR_SOURCE 13/**< interrupt of UHCI1, level*/ +#define ETS_TG0_T0_LEVEL_INTR_SOURCE 14/**< interrupt of TIMER_GROUP0, TIMER0, level, we would like use EDGE for timer if permission*/ +#define ETS_TG0_T1_LEVEL_INTR_SOURCE 15/**< interrupt of TIMER_GROUP0, TIMER1, level, we would like use EDGE for timer if permission*/ +#define ETS_TG0_WDT_LEVEL_INTR_SOURCE 16/**< interrupt of TIMER_GROUP0, WATCHDOG, level*/ +#define ETS_TG0_LACT_LEVEL_INTR_SOURCE 17/**< interrupt of TIMER_GROUP0, LACT, level*/ +#define ETS_TG1_T0_LEVEL_INTR_SOURCE 18/**< interrupt of TIMER_GROUP1, TIMER0, level, we would like use EDGE for timer if permission*/ +#define ETS_TG1_T1_LEVEL_INTR_SOURCE 19/**< interrupt of TIMER_GROUP1, TIMER1, level, we would like use EDGE for timer if permission*/ +#define ETS_TG1_WDT_LEVEL_INTR_SOURCE 20/**< interrupt of TIMER_GROUP1, WATCHDOG, level*/ +#define ETS_TG1_LACT_LEVEL_INTR_SOURCE 21/**< interrupt of TIMER_GROUP1, LACT, level*/ +#define ETS_GPIO_INTR_SOURCE 22/**< interrupt of GPIO, level*/ +#define ETS_GPIO_NMI_SOURCE 23/**< interrupt of GPIO, NMI*/ +#define ETS_FROM_CPU_INTR0_SOURCE 24/**< interrupt0 generated from a CPU, level*/ /* Used for FreeRTOS */ +#define ETS_FROM_CPU_INTR1_SOURCE 25/**< interrupt1 generated from a CPU, level*/ /* Used for FreeRTOS */ +#define ETS_FROM_CPU_INTR2_SOURCE 26/**< interrupt2 generated from a CPU, level*/ /* Used for DPORT Access */ +#define ETS_FROM_CPU_INTR3_SOURCE 27/**< interrupt3 generated from a CPU, level*/ /* Used for DPORT Access */ +#define ETS_SPI0_INTR_SOURCE 28/**< interrupt of SPI0, level, SPI0 is for Cache Access, do not use this*/ +#define ETS_SPI1_INTR_SOURCE 29/**< interrupt of SPI1, level, SPI1 is for flash read/write, do not use this*/ +#define ETS_SPI2_INTR_SOURCE 30/**< interrupt of SPI2, level*/ +#define ETS_SPI3_INTR_SOURCE 31/**< interrupt of SPI3, level*/ +#define ETS_I2S0_INTR_SOURCE 32/**< interrupt of I2S0, level*/ +#define ETS_I2S1_INTR_SOURCE 33/**< interrupt of I2S1, level*/ +#define ETS_UART0_INTR_SOURCE 34/**< interrupt of UART0, level*/ +#define ETS_UART1_INTR_SOURCE 35/**< interrupt of UART1, level*/ +#define ETS_UART2_INTR_SOURCE 36/**< interrupt of UART2, level*/ +#define ETS_SDIO_HOST_INTR_SOURCE 37/**< interrupt of SD/SDIO/MMC HOST, level*/ +#define ETS_ETH_MAC_INTR_SOURCE 38/**< interrupt of ethernet mac, level*/ +#define ETS_PWM0_INTR_SOURCE 39/**< interrupt of PWM0, level, Reserved*/ +#define ETS_PWM1_INTR_SOURCE 40/**< interrupt of PWM1, level, Reserved*/ +#define ETS_PWM2_INTR_SOURCE 41/**< interrupt of PWM2, level*/ +#define ETS_PWM3_INTR_SOURCE 42/**< interruot of PWM3, level*/ +#define ETS_LEDC_INTR_SOURCE 43/**< interrupt of LED PWM, level*/ +#define ETS_EFUSE_INTR_SOURCE 44/**< interrupt of efuse, level, not likely to use*/ +#define ETS_CAN_INTR_SOURCE 45/**< interrupt of can, level*/ +#define ETS_RTC_CORE_INTR_SOURCE 46/**< interrupt of rtc core, level, include rtc watchdog*/ +#define ETS_RMT_INTR_SOURCE 47/**< interrupt of remote controller, level*/ +#define ETS_PCNT_INTR_SOURCE 48/**< interrupt of pluse count, level*/ +#define ETS_I2C_EXT0_INTR_SOURCE 49/**< interrupt of I2C controller1, level*/ +#define ETS_I2C_EXT1_INTR_SOURCE 50/**< interrupt of I2C controller0, level*/ +#define ETS_RSA_INTR_SOURCE 51/**< interrupt of RSA accelerator, level*/ +#define ETS_SPI1_DMA_INTR_SOURCE 52/**< interrupt of SPI1 DMA, SPI1 is for flash read/write, do not use this*/ +#define ETS_SPI2_DMA_INTR_SOURCE 53/**< interrupt of SPI2 DMA, level*/ +#define ETS_SPI3_DMA_INTR_SOURCE 54/**< interrupt of SPI3 DMA, level*/ +#define ETS_WDT_INTR_SOURCE 55/**< will be cancelled*/ +#define ETS_TIMER1_INTR_SOURCE 56/**< will be cancelled*/ +#define ETS_TIMER2_INTR_SOURCE 57/**< will be cancelled*/ +#define ETS_TG0_T0_EDGE_INTR_SOURCE 58/**< interrupt of TIMER_GROUP0, TIMER0, EDGE*/ +#define ETS_TG0_T1_EDGE_INTR_SOURCE 59/**< interrupt of TIMER_GROUP0, TIMER1, EDGE*/ +#define ETS_TG0_WDT_EDGE_INTR_SOURCE 60/**< interrupt of TIMER_GROUP0, WATCH DOG, EDGE*/ +#define ETS_TG0_LACT_EDGE_INTR_SOURCE 61/**< interrupt of TIMER_GROUP0, LACT, EDGE*/ +#define ETS_TG1_T0_EDGE_INTR_SOURCE 62/**< interrupt of TIMER_GROUP1, TIMER0, EDGE*/ +#define ETS_TG1_T1_EDGE_INTR_SOURCE 63/**< interrupt of TIMER_GROUP1, TIMER1, EDGE*/ +#define ETS_TG1_WDT_EDGE_INTR_SOURCE 64/**< interrupt of TIMER_GROUP1, WATCHDOG, EDGE*/ +#define ETS_TG1_LACT_EDGE_INTR_SOURCE 65/**< interrupt of TIMER_GROUP0, LACT, EDGE*/ +#define ETS_MMU_IA_INTR_SOURCE 66/**< interrupt of MMU Invalid Access, LEVEL*/ +#define ETS_MPU_IA_INTR_SOURCE 67/**< interrupt of MPU Invalid Access, LEVEL*/ +#define ETS_CACHE_IA_INTR_SOURCE 68/**< interrupt of Cache Invalied Access, LEVEL*/ + + +#define ESP32_DPORT_CROSSCORE_INT_COUNT 4 +#define ESP32_INT_MATRIX_OUTPUTS 32 +#define ESP32_INT_MATRIX_INPUTS 69 +#define ESP32_CPU_COUNT 2 +#define ESP32_UART_COUNT 3 +#define ESP32_FRC_COUNT 2 +#define ESP32_TIMG_COUNT 2 +#define ESP32_SPI_COUNT 4 +#define ESP32_I2C_COUNT 2 +#define ESP32_RTC_CNTL_SCRATCH_REG_COUNT 8 + diff --git a/include/hw/misc/esp32_rng.h b/include/hw/misc/esp32_rng.h new file mode 100644 index 000000000000..1065310a3c16 --- /dev/null +++ b/include/hw/misc/esp32_rng.h @@ -0,0 +1,17 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32_reg.h" + + +#define TYPE_ESP32_RNG "misc.esp32.rng" +#define ESP32_RNG(obj) OBJECT_CHECK(Esp32RngState, (obj), TYPE_ESP32_RNG) + +typedef struct Esp32RngState { + SysBusDevice parent_obj; + MemoryRegion iomem; +} Esp32RngState; + +#define ESP32_RNG_BASE (DR_REG_WDEV_BASE + 0x144) + diff --git a/include/hw/misc/esp32_rsa.h b/include/hw/misc/esp32_rsa.h new file mode 100644 index 000000000000..31c8b0a6a29e --- /dev/null +++ b/include/hw/misc/esp32_rsa.h @@ -0,0 +1,46 @@ + #pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/esp32_reg.h" + +#define TYPE_ESP32_RSA "misc.esp32.rsa" +#define ESP32_RSA(obj) OBJECT_CHECK(Esp32RsaState, (obj), TYPE_ESP32_RSA) + +#define ESP32_RSA_MEM_BLK_SIZE 0x200 + +typedef struct Esp32RsaState { + SysBusDevice parent_obj; + MemoryRegion iomem; + + uint32_t rsa_m_mem[ESP32_RSA_MEM_BLK_SIZE / 4]; + uint32_t rsa_z_mem[ESP32_RSA_MEM_BLK_SIZE / 4]; + uint32_t rsa_y_mem[ESP32_RSA_MEM_BLK_SIZE / 4]; + uint32_t rsa_x_mem[ESP32_RSA_MEM_BLK_SIZE / 4]; + + struct { + void *rinv; + bool valid; + } cache; + + uint32_t rsa_mprime_reg; + uint32_t rsa_modexp_mode_reg; + uint32_t rsa_mult_mode_reg; + uint32_t rsa_clean_reg; + uint32_t rsa_q_int_reg; +} Esp32RsaState; + +REG32(RSA_MEM_M_BLOCK_BASE, 0x000) +REG32(RSA_MEM_RB_BLOCK_BASE, 0x200) +REG32(RSA_MEM_Z_BLOCK_BASE, 0x200) +REG32(RSA_MEM_Y_BLOCK_BASE, 0x400) +REG32(RSA_MEM_X_BLOCK_BASE, 0x600) +REG32(RSA_M_DASH_REG, 0x800) +REG32(RSA_MODEXP_MODE_REG, 0x804) +REG32(RSA_MODEXP_START_REG, 0x808) +REG32(RSA_MULT_MODE_REG, 0x80C) +REG32(RSA_MULT_START_REG, 0x810) +REG32(RSA_CLEAR_INTERRUPT_REG, 0x814) +REG32(RSA_QUERY_INTERRUPT_REG, 0x814) +REG32(RSA_QUERY_CLEAN_REG, 0x818) diff --git a/include/hw/misc/esp32_rtc_cntl.h b/include/hw/misc/esp32_rtc_cntl.h new file mode 100644 index 000000000000..cef7baceba4d --- /dev/null +++ b/include/hw/misc/esp32_rtc_cntl.h @@ -0,0 +1,118 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" + +#include "hw/misc/esp32_reg.h" +#define TYPE_ESP32_RTC_CNTL "misc.esp32.rtc_cntl" +#define ESP32_RTC_CNTL(obj) OBJECT_CHECK(Esp32RtcCntlState, (obj), TYPE_ESP32_RTC_CNTL) + +#define ESP32_RTC_DIG_RESET_GPIO "dig-reset" +#define ESP32_RTC_CPU_RESET_GPIO "cpu-reset" +#define ESP32_RTC_CPU_STALL_GPIO "cpu-stall" +#define ESP32_RTC_CLK_UPDATE_GPIO "clk-update" + +typedef enum Esp32ResetCause { + ESP32_POWERON_RESET = 1, + ESP32_SW_SYS_RESET = 3, + ESP32_OWDT_RESET = 4, + ESP32_DEEPSLEEP_RESET = 5, + ESP32_SDIO_RESET = 6, + ESP32_TG0WDT_SYS_RESET = 7, + ESP32_TG1WDT_SYS_RESET = 8, + ESP32_RTCWDT_SYS_RESET = 9, + ESP32_TGWDT_CPU_RESET = 11, + ESP32_SW_CPU_RESET = 12, + ESP32_RTCWDT_CPU_RESET = 13, + ESP32_EXT_CPU_RESET = 14, + ESP32_RTCWDT_BROWN_OUT_RESET = 15, + ESP32_RTCWDT_RTC_RESET = 16 +} Esp32ResetCause; + +typedef enum Esp32SocClkSel { + ESP32_SOC_CLK_XTAL = 0, + ESP32_SOC_CLK_PLL = 1, + ESP32_SOC_CLK_8M = 2, + ESP32_SOC_CLK_APLL = 3 +} Esp32SocClkSel; + +typedef enum Esp32FastClkSel { + ESP32_FAST_CLK_XTALD4 = 0, + ESP32_FAST_CLK_8M = 1 +} Esp32FastClkSel; + +typedef enum Esp32SlowClkSel { + ESP32_SLOW_CLK_RC = 0, + ESP32_SLOW_CLK_32KXTAL = 1, + ESP32_SLOW_CLK_8MD256 = 2 +} Esp32SlowClkSel; + +typedef struct Esp32RtcCntlState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + qemu_irq irq; + qemu_irq dig_reset_req; + qemu_irq cpu_reset_req[ESP32_CPU_COUNT]; + qemu_irq cpu_stall_req[ESP32_CPU_COUNT]; + qemu_irq clk_update; + bool cpu_stall_state[ESP32_CPU_COUNT]; + + uint32_t xtal_apb_freq; + uint32_t pll_apb_freq; + Esp32SocClkSel soc_clk; + Esp32FastClkSel rtc_fastclk; + uint32_t rtc_fastclk_freq; + Esp32SlowClkSel rtc_slowclk; + uint32_t rtc_slowclk_freq; + int64_t time_base_ns; + + uint32_t options0_reg; + uint64_t time_reg; + uint32_t sw_cpu_stall_reg; + uint32_t scratch_reg[ESP32_RTC_CNTL_SCRATCH_REG_COUNT]; + Esp32ResetCause reset_cause[ESP32_CPU_COUNT]; + bool stat_vector_sel[ESP32_CPU_COUNT]; +} Esp32RtcCntlState; + +REG32(RTC_CNTL_OPTIONS0, 0x00) + FIELD(RTC_CNTL_OPTIONS0, SW_SYS_RESET, 31, 1) + FIELD(RTC_CNTL_OPTIONS0, SW_PROCPU_RESET, 5, 1) + FIELD(RTC_CNTL_OPTIONS0, SW_APPCPU_RESET, 4, 1) + FIELD(RTC_CNTL_OPTIONS0, SW_STALL_PROCPU_C0, 2, 2) + FIELD(RTC_CNTL_OPTIONS0, SW_STALL_APPCPU_C0, 0, 2) + +REG32(RTC_CNTL_TIME_UPDATE, 0xc) + FIELD(RTC_CNTL_TIME_UPDATE, UPDATE, 31, 1) + FIELD(RTC_CNTL_TIME_UPDATE, VALID, 30, 1) +REG32(RTC_CNTL_TIME0, 0x10) +REG32(RTC_CNTL_TIME1, 0x14) + +REG32(RTC_CNTL_RESET_STATE, 0x34) + FIELD(RTC_CNTL_RESET_STATE, PROCPU_STAT_VECTOR_SEL, 13, 1) + FIELD(RTC_CNTL_RESET_STATE, APPCPU_STAT_VECTOR_SEL, 12, 1) + FIELD(RTC_CNTL_RESET_STATE, RESET_CAUSE_APPCPU, 6, 6) + FIELD(RTC_CNTL_RESET_STATE, RESET_CAUSE_PROCPU, 0, 6) + +REG32(RTC_CNTL_STORE0, 0x4c) +REG32(RTC_CNTL_STORE1, 0x50) +REG32(RTC_CNTL_STORE2, 0x54) +REG32(RTC_CNTL_STORE3, 0x58) + +REG32(RTC_CNTL_CLK_CONF, 0x70) + FIELD(RTC_CNTL_CLK_CONF, ANA_CLK_RTC_SEL, 30, 2) + FIELD(RTC_CNTL_CLK_CONF, FAST_CLK_RTC_SEL, 29, 1) + FIELD(RTC_CNTL_CLK_CONF, SOC_CLK_SEL, 27, 2) + +REG32(RTC_CNTL_SW_CPU_STALL, 0xac) + FIELD(RTC_CNTL_SW_CPU_STALL, PROCPU_C1, 26, 6) + FIELD(RTC_CNTL_SW_CPU_STALL, APPCPU_C1, 20, 6) + +REG32(RTC_CNTL_STORE4, 0xb0) +REG32(RTC_CNTL_STORE5, 0xb4) +REG32(RTC_CNTL_STORE6, 0xb8) +REG32(RTC_CNTL_STORE7, 0xbc) +REG32(RTC_CNTL_DATE, 0x13c) + +#define ESP32_RTC_CNTL_SIZE (A_RTC_CNTL_DATE + 4) diff --git a/include/hw/misc/esp32_sha.h b/include/hw/misc/esp32_sha.h new file mode 100644 index 000000000000..7a7594127dcc --- /dev/null +++ b/include/hw/misc/esp32_sha.h @@ -0,0 +1,36 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/esp32_reg.h" +#include "crypto/sha512_i.h" +#include "crypto/sha384_i.h" +#include "crypto/sha256_i.h" +#include "crypto/sha1_i.h" + +#define TYPE_ESP32_SHA "misc.esp32.sha" +#define ESP32_SHA(obj) OBJECT_CHECK(Esp32ShaState, (obj), TYPE_ESP32_SHA) + +#define ESP32_SHA_TEXT_REG_CNT 32 + +typedef struct Esp32ShaState { + SysBusDevice parent_obj; + MemoryRegion iomem; + uint32_t text[ESP32_SHA_TEXT_REG_CNT]; + struct sha512_state sha512; + struct sha512_state sha384; + struct sha256_state sha256; + struct sha1_state sha1; +} Esp32ShaState; + +#define SHA_REG_GROUP(name, base) \ + REG32(name ## _START, (base)) \ + REG32(name ## _CONTINUE, (base + 0x4)) \ + REG32(name ## _LOAD, (base + 0x8)) \ + REG32(name ## _BUSY, (base + 0xc)) + +SHA_REG_GROUP(SHA1, 0x80) +SHA_REG_GROUP(SHA256, 0x90) +SHA_REG_GROUP(SHA384, 0xa0) +SHA_REG_GROUP(SHA512, 0xb0) diff --git a/include/hw/misc/esp32_unknown.h b/include/hw/misc/esp32_unknown.h new file mode 100644 index 000000000000..8fef1140d8a5 --- /dev/null +++ b/include/hw/misc/esp32_unknown.h @@ -0,0 +1,15 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/esp32_reg.h" + +#define TYPE_ESP32_UNKNOWN "misc.esp32.unknown" +#define ESP32_UNKNOWN(obj) OBJECT_CHECK(Esp32UnknownState, (obj), TYPE_ESP32_UNKNOWN) + +typedef struct Esp32UnknownState { + SysBusDevice parent_obj; + MemoryRegion iomem; +} Esp32UnknownState; + diff --git a/include/hw/misc/esp32_wifi.h b/include/hw/misc/esp32_wifi.h new file mode 100644 index 000000000000..a8c86d4dd08f --- /dev/null +++ b/include/hw/misc/esp32_wifi.h @@ -0,0 +1,65 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32_reg.h" +#include "sysemu/sysemu.h" +#include "net/net.h" + +#define TYPE_ESP32_WIFI "misc.esp32_wifi" +#define ESP32_WIFI(obj) OBJECT_CHECK(Esp32WifiState, (obj), TYPE_ESP32_WIFI) + +typedef struct dma_list_item { + unsigned size:12; + unsigned length:12; + unsigned :6; + unsigned eof:1; + unsigned owner:1; + uint32_t address; + uint32_t next; +} QEMU_PACKED dma_list_item; + +typedef struct Esp32WifiState { + SysBusDevice parent_obj; + MemoryRegion iomem; + int raw_interrupt; + qemu_irq irq; + uint32_t mem[1024]; + int dma_inlink_address; + uint32_t ap_state; + int inject_queue_size; + struct mac80211_frame *inject_queue; + int inject_timer_running; + unsigned int inject_sequence_number; + int beacon_ap; + + hwaddr receive_queue_address; + uint32_t receive_queue_count; + NICConf conf; + NICState *nic; + // various timers + QEMUTimer *beacon_timer; + QEMUTimer *inject_timer; + uint8_t ipaddr[4]; + uint8_t macaddr[6]; + + uint8_t ap_ipaddr[4]; + uint8_t ap_macaddr[6]; + + uint8_t associated_ap_macaddr[6]; + +} Esp32WifiState; + + +void Esp32_WLAN_handle_frame(Esp32WifiState *s, struct mac80211_frame *frame); +void Esp32_WLAN_setup_ap(DeviceState *dev,Esp32WifiState *s); +void Esp32_sendFrame(Esp32WifiState *s, struct mac80211_frame *frame,int length, int signal_strength); + +REG32(WIFI_DMA_IN_STATUS, 0x84); +REG32(WIFI_DMA_INLINK, 0x88); +REG32(WIFI_DMA_INT_STATUS, 0xc48); +REG32(WIFI_DMA_INT_CLR, 0xc4c); +REG32(WIFI_STATUS, 0xcc8); +REG32(WIFI_DMA_OUTLINK, 0xd20); +REG32(WIFI_DMA_OUT_STATUS, 0xd24); diff --git a/include/hw/misc/esp32c3_aes.h b/include/hw/misc/esp32c3_aes.h new file mode 100644 index 000000000000..6469866ea9e1 --- /dev/null +++ b/include/hw/misc/esp32c3_aes.h @@ -0,0 +1,139 @@ +/* + * ESP32-C3 AES emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/dma/esp32c3_gdma.h" + +#define TYPE_ESP32C3_AES "misc.esp32c3.aes" +#define ESP32C3_AES(obj) OBJECT_CHECK(ESP32C3AesState, (obj), TYPE_ESP32C3_AES) + +#define ESP32C3_AES_REGS_SIZE (A_AES_DMA_EXIT_REG + 4) + +#define ESP32C3_AES_TEXT_REG_CNT 4 +#define ESP32C3_AES_KEY_REG_CNT 8 +#define ESP32C3_AES_IV_REG_CNT 16 + +#define ESP32C3_AES_IDLE 0 +#define ESP32C3_AES_WORK 1 +#define ESP32C3_AES_DONE 2 + +/** + * Encryption and decryption modes + */ +#define ESP32C3_AES_MODE_128_ENC 0 +#define ESP32C3_AES_MODE_256_ENC 2 +#define ESP32C3_AES_MODE_128_DEC 4 +#define ESP32C3_AES_MODE_256_DEC 6 + + +/** + * Block Cipher modes + */ +#define ESP32C3_AES_ECB_CIPHER 0 +#define ESP32C3_AES_CBC_CIPHER 1 +#define ESP32C3_AES_OFB_CIPHER 2 +#define ESP32C3_AES_CTR_CIPHER 3 +#define ESP32C3_AES_CFB8_CIPHER 4 +#define ESP32C3_AES_CFB128_CIPHER 5 +#define ESP32C3_AES_CIPHER_COUNT 6 + + +typedef struct ESP32C3AesState { + SysBusDevice parent_object; + MemoryRegion iomem; + + uint32_t key[ESP32C3_AES_KEY_REG_CNT]; + uint32_t text_in[ESP32C3_AES_TEXT_REG_CNT]; + uint32_t text_out[ESP32C3_AES_TEXT_REG_CNT]; + uint8_t iv_mem[ESP32C3_AES_IV_REG_CNT]; + + uint32_t mode_reg; + uint32_t state_reg; + uint32_t dma_enable_reg; + uint32_t block_mode_reg; + uint32_t block_num_reg; + uint32_t inc_sel_reg; + + uint32_t int_ena_reg; + qemu_irq irq; + + /* Public: must be set by the machine before realizing current instance */ + ESP32C3GdmaState *gdma; +} ESP32C3AesState; + + +REG32(AES_KEY_0_REG, 0x00) +REG32(AES_KEY_1_REG, 0x04) +REG32(AES_KEY_2_REG, 0x08) +REG32(AES_KEY_3_REG, 0x0C) +REG32(AES_KEY_4_REG, 0x10) +REG32(AES_KEY_5_REG, 0x14) +REG32(AES_KEY_6_REG, 0x18) +REG32(AES_KEY_7_REG, 0x1C) + +REG32(AES_TEXT_IN_0_REG, 0x20) +REG32(AES_TEXT_IN_1_REG, 0x24) +REG32(AES_TEXT_IN_2_REG, 0x28) +REG32(AES_TEXT_IN_3_REG, 0x2C) + +REG32(AES_TEXT_OUT_0_REG, 0x30) +REG32(AES_TEXT_OUT_1_REG, 0x34) +REG32(AES_TEXT_OUT_2_REG, 0x38) +REG32(AES_TEXT_OUT_3_REG, 0x3C) + + +REG32(AES_IV_MEM_0_REG, 0x50) +REG32(AES_IV_MEM_1_REG, 0x51) +REG32(AES_IV_MEM_2_REG, 0x52) +REG32(AES_IV_MEM_3_REG, 0x53) +REG32(AES_IV_MEM_4_REG, 0x54) +REG32(AES_IV_MEM_5_REG, 0x55) +REG32(AES_IV_MEM_6_REG, 0x56) +REG32(AES_IV_MEM_7_REG, 0x57) +REG32(AES_IV_MEM_8_REG, 0x58) +REG32(AES_IV_MEM_9_REG, 0x59) +REG32(AES_IV_MEM_10_REG, 0x5a) +REG32(AES_IV_MEM_11_REG, 0x5b) +REG32(AES_IV_MEM_12_REG, 0x5c) +REG32(AES_IV_MEM_13_REG, 0x5d) +REG32(AES_IV_MEM_14_REG, 0x5e) +REG32(AES_IV_MEM_15_REG, 0x5f) + + +REG32(AES_MODE_REG, 0x40) + FIELD(AES_MODE_REG, AES_MODE, 0, 3) + +REG32(AES_TRIGGER_REG, 0x48) + FIELD(AES_TRIGGER_REG, AES_TRIGGER, 0, 1) + +REG32(AES_STATE_REG, 0x4C) + FIELD(AES_STATE_REG, AES_STATE, 0, 2) + +REG32(AES_DMA_ENA_REG, 0x90) + FIELD(AES_DMA_ENA_REG, AES_DMA_ENA, 0, 1) + +REG32(AES_BLK_MODE_REG, 0x94) + FIELD(AES_BLK_MODE_REG, AES_BLOCK_MODE, 0, 3) + +REG32(AES_BLK_NUM_REG, 0x98) + +REG32(AES_INC_SEL_REG, 0x9C) + FIELD(AES_INC_SEL_REG, AES_INC_SEL, 0, 1) + +REG32(AES_INT_CLR_REG, 0xAC) + FIELD(AES_INT_CLR_REG, AES_INT_CLR, 0, 1) + +REG32(AES_INT_ENA_REG, 0xB0) + FIELD(AES_INT_ENA_REG, AES_INT_ENA, 0, 1) + +REG32(AES_DMA_EXIT_REG, 0xB8) diff --git a/include/hw/misc/esp32c3_cache.h b/include/hw/misc/esp32c3_cache.h new file mode 100644 index 000000000000..ccc05fd1b941 --- /dev/null +++ b/include/hw/misc/esp32c3_cache.h @@ -0,0 +1,352 @@ +#pragma once + +#include "hw/misc/esp32c3_reg.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/registerfields.h" + +#define TYPE_ESP32C3_CACHE "esp32c3.cache" +#define ESP32C3_CACHE(obj) OBJECT_CHECK(ESP32C3CacheState, (obj), TYPE_ESP32C3_CACHE) +#define ESP32C3_CACHE_GET_CLASS(obj) OBJECT_GET_CLASS(ESP32C3CacheState, obj, TYPE_ESP32C3_CACHE) +#define ESP32C3_CACHE_CLASS(klass) OBJECT_CLASS_CHECK(ESP32C3CacheState, klass, TYPE_ESP32C3_CACHE) + +#define ESP32C3_DCACHE_BASE 0x3c000000 +#define ESP32C3_ICACHE_BASE 0x42000000 + +/* The MMU is shared between by both the ICache and the DCache */ +#define ESP32C3_MMU_SIZE 0x200 + +/* Each MMU virtual page is 64KB big on the ESP32C3 */ +#define ESP32C3_PAGE_SIZE (64*1024) + +/* Offset of the MMU table in I/O memory range + * As the MMU table is mapped in the same MemoryRegion as the Cache I/O registers, its base offset + * will not be 0 */ +#define ESP32C3_MMU_TABLE_OFFSET (DR_REG_MMU_TABLE - DR_REG_EXTMEM_BASE) + +/* Number of entries count in the table size */ +#define ESP32C3_MMU_TABLE_ENTRY_COUNT (ESP32C3_MMU_SIZE/sizeof(uint32_t)) + +typedef union ESP32C3MMUEntry { + struct { + uint32_t page_number : 8; + uint32_t invalid : 1; + uint32_t reserved : 23; /* Must always be 0 */ + }; + uint32_t val; +} ESP32C3MMUEntry; + +_Static_assert(sizeof(ESP32C3MMUEntry) == sizeof(uint32_t), "MMU Entry size must be 4 bytes"); + +/** + * The external memory region on the ESP32-C3 is 2x8MB, but both regions are shared (data & instructions) + */ +#define ESP32C3_EXTMEM_REGION_SIZE 0x800000 + +/** + * The cache on ESP32-C3 has a size of 16KB, and the block size is 32 bytes (1024 blocks) + */ +#define ESP32C3_CACHE_BLOCK_SIZE 32 +#define ESP32C3_CACHE_BLOCK_COUNT 512 +#define ESP32C3_CACHE_SIZE (ESP32C3_CACHE_BLOCK_COUNT * ESP32C3_CACHE_BLOCK_SIZE) + +/** + * Size of the Cache I/O registers area + */ +#define TYPE_ESP32C3_CACHE_IO_SIZE 0x1000 + +/** + * Even though the size of the I/O range for extmem cache is 0x1000, the registers actually go + * up to 0x100. + */ +#define ESP32C3_CACHE_REG_COUNT (0x100 / sizeof(uint32_t)) + +/** + * Convert a register address to its index in the registers array + */ +#define ESP32C3_CACHE_REG_IDX(addr) ((addr) / sizeof(uint32_t)) + +typedef struct { + SysBusDevice parent; + BlockBackend *flash_blk; + MemoryRegion iomem; + + bool icache_enable; + hwaddr dcache_base; + hwaddr icache_base; + MemoryRegion dcache; + MemoryRegion icache; + + /* Registers for controlling the cache */ + uint32_t regs[ESP32C3_CACHE_REG_COUNT]; + + /* Define the MMU itself as an array, it shall be accessible from address ESP32C3_MMU_TABLE */ + ESP32C3MMUEntry mmu[ESP32C3_MMU_TABLE_ENTRY_COUNT]; +} ESP32C3CacheState; + +/* Assert that the size of the MMU table in the structure is of size ESP32C3_MMU_SIZE */ +_Static_assert(sizeof(ESP32C3CacheState) - offsetof(ESP32C3CacheState, mmu) == ESP32C3_MMU_SIZE, + "The size of `mmu` field in structure ESP32C3CacheState must be equal to ESP32C3_MMU_SIZE"); + + +REG32(EXTMEM_ICACHE_CTRL, 0x000) + FIELD(EXTMEM_ICACHE_CTRL, ENABLE, 0, 1) + +REG32(EXTMEM_ICACHE_CTRL1, 0x004) + FIELD(EXTMEM_ICACHE_CTRL1, SHUT_DBUS, 1, 1) + FIELD(EXTMEM_ICACHE_CTRL1, SHUT_IBUS, 0, 1) + +REG32(EXTMEM_ICACHE_TAG_POWER_CTRL, 0x008) + FIELD(EXTMEM_ICACHE_TAG_POWER_CTRL, TAG_MEM_FORCE_PU, 2, 1) + FIELD(EXTMEM_ICACHE_TAG_POWER_CTRL, TAG_MEM_FORCE_PD, 1, 1) + FIELD(EXTMEM_ICACHE_TAG_POWER_CTRL, TAG_MEM_FORCE_ON, 0, 1) + +REG32(EXTMEM_ICACHE_PRELOCK_CTRL, 0x00C) + FIELD(EXTMEM_ICACHE_PRELOCK_CTRL, PRELOCK_SCT1_EN, 1, 1) + FIELD(EXTMEM_ICACHE_PRELOCK_CTRL, PRELOCK_SCT0_EN, 0, 1) + +REG32(EXTMEM_ICACHE_PRELOCK_SCT0_ADDR, 0x010) + FIELD(EXTMEM_ICACHE_PRELOCK_SCT0_ADDR, PRELOCK_SCT0_ADDR, 0, 32) + +REG32(EXTMEM_ICACHE_PRELOCK_SCT1_ADDR, 0x014) + FIELD(EXTMEM_ICACHE_PRELOCK_SCT1_ADDR, PRELOCK_SCT1_ADDR, 0, 32) + +REG32(EXTMEM_ICACHE_PRELOCK_SCT_SIZE, 0x018) + FIELD(EXTMEM_ICACHE_PRELOCK_SCT_SIZE, PRELOCK_SCT0_SIZE, 16, 16) + FIELD(EXTMEM_ICACHE_PRELOCK_SCT_SIZE, PRELOCK_SCT1_SIZE, 0, 16) + +REG32(EXTMEM_ICACHE_LOCK_CTRL, 0x01C) + FIELD(EXTMEM_ICACHE_LOCK_CTRL, LOCK_DONE, 2, 1) + FIELD(EXTMEM_ICACHE_LOCK_CTRL, UNLOCK_ENA, 1, 1) + FIELD(EXTMEM_ICACHE_LOCK_CTRL, LOCK_ENA, 0, 1) + +REG32(EXTMEM_ICACHE_LOCK_ADDR, 0x020) + FIELD(EXTMEM_ICACHE_LOCK_ADDR, LOCK_ADDR, 0, 32) + +REG32(EXTMEM_ICACHE_LOCK_SIZE, 0x024) + FIELD(EXTMEM_ICACHE_LOCK_SIZE, LOCK_SIZE, 0, 16) + +REG32(EXTMEM_ICACHE_SYNC_CTRL, 0x028) + FIELD(EXTMEM_ICACHE_SYNC_CTRL, SYNC_DONE, 1, 1) + FIELD(EXTMEM_ICACHE_SYNC_CTRL, INVALIDATE_ENA, 0, 1) + +REG32(EXTMEM_ICACHE_SYNC_ADDR, 0x02C) + FIELD(EXTMEM_ICACHE_SYNC_ADDR, SYNC_ADDR, 0, 32) + +REG32(EXTMEM_ICACHE_SYNC_SIZE, 0x030) + FIELD(EXTMEM_ICACHE_SYNC_SIZE, SYNC_SIZE, 0, 23) + +REG32(EXTMEM_ICACHE_PRELOAD_CTRL, 0x034) + FIELD(EXTMEM_ICACHE_PRELOAD_CTRL, PRELOAD_ORDER, 2, 1) + FIELD(EXTMEM_ICACHE_PRELOAD_CTRL, PRELOAD_DONE, 1, 1) + FIELD(EXTMEM_ICACHE_PRELOAD_CTRL, PRELOAD_ENA, 0, 1) + +REG32(EXTMEM_ICACHE_PRELOAD_ADDR, 0x038) + FIELD(EXTMEM_ICACHE_PRELOAD_ADDR, PRELOAD_ADDR, 0, 32) + +REG32(EXTMEM_ICACHE_PRELOAD_SIZE, 0x03C) + FIELD(EXTMEM_ICACHE_PRELOAD_SIZE, PRELOAD_SIZE, 0, 16) + +REG32(EXTMEM_ICACHE_AUTOLOAD_CTRL, 0x040) + FIELD(EXTMEM_ICACHE_AUTOLOAD_CTRL, AUTOLOAD_RQST, 5, 2) + FIELD(EXTMEM_ICACHE_AUTOLOAD_CTRL, AUTOLOAD_ORDER, 4, 1) + FIELD(EXTMEM_ICACHE_AUTOLOAD_CTRL, AUTOLOAD_DONE, 3, 1) + FIELD(EXTMEM_ICACHE_AUTOLOAD_CTRL, AUTOLOAD_ENA, 2, 1) + FIELD(EXTMEM_ICACHE_AUTOLOAD_CTRL, AUTOLOAD_SCT1_ENA, 1, 1) + FIELD(EXTMEM_ICACHE_AUTOLOAD_CTRL, AUTOLOAD_SCT0_ENA, 0, 1) + +REG32(EXTMEM_ICACHE_AUTOLOAD_SCT0_ADDR, 0x044) + FIELD(EXTMEM_ICACHE_AUTOLOAD_SCT0_ADDR, AUTOLOAD_SCT0_ADDR, 0, 32) + +REG32(EXTMEM_ICACHE_AUTOLOAD_SCT0_SIZE, 0x048) + FIELD(EXTMEM_ICACHE_AUTOLOAD_SCT0_SIZE, AUTOLOAD_SCT0_SIZE, 0, 27) + +REG32(EXTMEM_ICACHE_AUTOLOAD_SCT1_ADDR, 0x04C) + FIELD(EXTMEM_ICACHE_AUTOLOAD_SCT1_ADDR, AUTOLOAD_SCT1_ADDR, 0, 32) + +REG32(EXTMEM_ICACHE_AUTOLOAD_SCT1_SIZE, 0x050) + FIELD(EXTMEM_ICACHE_AUTOLOAD_SCT1_SIZE, AUTOLOAD_SCT1_SIZE, 0, 27) + +REG32(EXTMEM_IBUS_TO_FLASH_START_VADDR, 0x054) + FIELD(EXTMEM_IBUS_TO_FLASH_START_VADDR, IBUS_TO_FLASH_START_VADDR, 0, 32) + +REG32(EXTMEM_IBUS_TO_FLASH_END_VADDR, 0x058) + FIELD(EXTMEM_IBUS_TO_FLASH_END_VADDR, IBUS_TO_FLASH_END_VADDR, 0, 32) + +REG32(EXTMEM_DBUS_TO_FLASH_START_VADDR, 0x05C) + FIELD(EXTMEM_DBUS_TO_FLASH_START_VADDR, DBUS_TO_FLASH_START_VADDR, 0, 32) + +REG32(EXTMEM_DBUS_TO_FLASH_END_VADDR, 0x060) + FIELD(EXTMEM_DBUS_TO_FLASH_END_VADDR, DBUS_TO_FLASH_END_VADDR, 0, 32) + +REG32(EXTMEM_CACHE_ACS_CNT_CLR, 0x064) + FIELD(EXTMEM_CACHE_ACS_CNT_CLR, DBUS_ACS_CNT_CLR, 1, 1) + FIELD(EXTMEM_CACHE_ACS_CNT_CLR, IBUS_ACS_CNT_CLR, 0, 1) + +REG32(EXTMEM_IBUS_ACS_MISS_CNT, 0x068) + FIELD(EXTMEM_IBUS_ACS_MISS_CNT, IBUS_ACS_MISS_CNT, 0, 32) + +REG32(EXTMEM_IBUS_ACS_CNT, 0x06C) + FIELD(EXTMEM_IBUS_ACS_CNT, IBUS_ACS_CNT, 0, 32) + +REG32(EXTMEM_DBUS_ACS_FLASH_MISS_CNT, 0x070) + FIELD(EXTMEM_DBUS_ACS_FLASH_MISS_CNT, DBUS_ACS_FLASH_MISS_CNT, 0, 32) + +REG32(EXTMEM_DBUS_ACS_CNT, 0x074) + FIELD(EXTMEM_DBUS_ACS_CNT, DBUS_ACS_CNT, 0, 32) + +REG32(EXTMEM_CACHE_ILG_INT_ENA, 0x078) + FIELD(EXTMEM_CACHE_ILG_INT_ENA, DBUS_CNT_OVF_INT_ENA, 8, 1) + FIELD(EXTMEM_CACHE_ILG_INT_ENA, IBUS_CNT_OVF_INT_ENA, 7, 1) + FIELD(EXTMEM_CACHE_ILG_INT_ENA, MMU_ENTRY_FAULT_INT_ENA, 5, 1) + FIELD(EXTMEM_CACHE_ILG_INT_ENA, ICACHE_PRELOAD_OP_FAULT_INT_ENA, 1, 1) + FIELD(EXTMEM_CACHE_ILG_INT_ENA, ICACHE_SYNC_OP_FAULT_INT_ENA, 0, 1) + +REG32(EXTMEM_CACHE_ILG_INT_CLR, 0x07C) + FIELD(EXTMEM_CACHE_ILG_INT_CLR, DBUS_CNT_OVF_INT_CLR, 8, 1) + FIELD(EXTMEM_CACHE_ILG_INT_CLR, IBUS_CNT_OVF_INT_CLR, 7, 1) + FIELD(EXTMEM_CACHE_ILG_INT_CLR, MMU_ENTRY_FAULT_INT_CLR, 5, 1) + FIELD(EXTMEM_CACHE_ILG_INT_CLR, ICACHE_PRELOAD_OP_FAULT_INT_CLR, 1, 1) + FIELD(EXTMEM_CACHE_ILG_INT_CLR, ICACHE_SYNC_OP_FAULT_INT_CLR, 0, 1) + +REG32(EXTMEM_CACHE_ILG_INT_ST, 0x080) + FIELD(EXTMEM_CACHE_ILG_INT_ST, DBUS_ACS_FLASH_MISS_CNT_OVF_ST, 10, 1) + FIELD(EXTMEM_CACHE_ILG_INT_ST, DBUS_ACS_CNT_OVF_ST, 9, 1) + FIELD(EXTMEM_CACHE_ILG_INT_ST, IBUS_ACS_MISS_CNT_OVF_ST, 8, 1) + FIELD(EXTMEM_CACHE_ILG_INT_ST, IBUS_ACS_CNT_OVF_ST, 7, 1) + FIELD(EXTMEM_CACHE_ILG_INT_ST, MMU_ENTRY_FAULT_ST, 5, 1) + FIELD(EXTMEM_CACHE_ILG_INT_ST, ICACHE_PRELOAD_OP_FAULT_ST, 1, 1) + FIELD(EXTMEM_CACHE_ILG_INT_ST, ICACHE_SYNC_OP_FAULT_ST, 0, 1) + +REG32(EXTMEM_CORE0_ACS_CACHE_INT_ENA, 0x084) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_ENA, CORE0_DBUS_WR_IC_INT_ENA, 5, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_ENA, CORE0_DBUS_REJECT_INT_ENA, 4, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_ENA, CORE0_DBUS_ACS_MSK_IC_INT_ENA, 3, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_ENA, CORE0_IBUS_REJECT_INT_ENA, 2, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_ENA, CORE0_IBUS_WR_IC_INT_ENA, 1, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_ENA, CORE0_IBUS_ACS_MSK_IC_INT_ENA, 0, 1) + +REG32(EXTMEM_CORE0_ACS_CACHE_INT_CLR, 0x088) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_CLR, CORE0_DBUS_WR_IC_INT_CLR, 5, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_CLR, CORE0_DBUS_REJECT_INT_CLR, 4, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_CLR, CORE0_DBUS_ACS_MSK_IC_INT_CLR, 3, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_CLR, CORE0_IBUS_REJECT_INT_CLR, 2, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_CLR, CORE0_IBUS_WR_IC_INT_CLR, 1, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_CLR, CORE0_IBUS_ACS_MSK_IC_INT_CLR, 0, 1) + +REG32(EXTMEM_CORE0_ACS_CACHE_INT_ST, 0x08C) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_ST, CORE0_DBUS_WR_ICACHE_ST, 5, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_ST, CORE0_DBUS_REJECT_ST, 4, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_ST, CORE0_DBUS_ACS_MSK_ICACHE_ST, 3, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_ST, CORE0_IBUS_REJECT_ST, 2, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_ST, CORE0_IBUS_WR_ICACHE_ST, 1, 1) + FIELD(EXTMEM_CORE0_ACS_CACHE_INT_ST, CORE0_IBUS_ACS_MSK_ICACHE_ST, 0, 1) + +REG32(EXTMEM_CORE0_DBUS_REJECT_ST, 0x090) + FIELD(EXTMEM_CORE0_DBUS_REJECT_ST, CORE0_DBUS_WORLD, 3, 1) + FIELD(EXTMEM_CORE0_DBUS_REJECT_ST, CORE0_DBUS_ATTR, 0, 3) + +REG32(EXTMEM_CORE0_DBUS_REJECT_VADDR, 0x094) + FIELD(EXTMEM_CORE0_DBUS_REJECT_VADDR, CORE0_DBUS_VADDR, 0, 32) + +REG32(EXTMEM_CORE0_IBUS_REJECT_ST, 0x098) + FIELD(EXTMEM_CORE0_IBUS_REJECT_ST, CORE0_IBUS_WORLD, 3, 1) + FIELD(EXTMEM_CORE0_IBUS_REJECT_ST, CORE0_IBUS_ATTR, 0, 3) + +REG32(EXTMEM_CORE0_IBUS_REJECT_VADDR, 0x09C) + FIELD(EXTMEM_CORE0_IBUS_REJECT_VADDR, CORE0_IBUS_VADDR, 0, 32) + +REG32(EXTMEM_CACHE_MMU_FAULT_CONTENT, 0x0A0) + FIELD(EXTMEM_CACHE_MMU_FAULT_CONTENT, CACHE_MMU_FAULT_CODE, 10, 4) + FIELD(EXTMEM_CACHE_MMU_FAULT_CONTENT, CACHE_MMU_FAULT_CONTENT, 0, 10) + +REG32(EXTMEM_CACHE_MMU_FAULT_VADDR, 0x0A4) + FIELD(EXTMEM_CACHE_MMU_FAULT_VADDR, CACHE_MMU_FAULT_VADDR, 0, 32) + +REG32(EXTMEM_CACHE_WRAP_AROUND_CTRL, 0x0A8) + FIELD(EXTMEM_CACHE_WRAP_AROUND_CTRL, CACHE_FLASH_WRAP_AROUND, 0, 1) + +REG32(EXTMEM_CACHE_MMU_POWER_CTRL, 0x0AC) + FIELD(EXTMEM_CACHE_MMU_POWER_CTRL, CACHE_MMU_MEM_FORCE_PU, 2, 1) + FIELD(EXTMEM_CACHE_MMU_POWER_CTRL, CACHE_MMU_MEM_FORCE_PD, 1, 1) + FIELD(EXTMEM_CACHE_MMU_POWER_CTRL, CACHE_MMU_MEM_FORCE_ON, 0, 1) + +REG32(EXTMEM_CACHE_STATE, 0x0B0) + FIELD(EXTMEM_CACHE_STATE, ICACHE_STATE, 0, 12) + +REG32(EXTMEM_CACHE_ENCRYPT_DECRYPT_RECORD_DISABLE, 0x0B4) + FIELD(EXTMEM_CACHE_ENCRYPT_DECRYPT_RECORD_DISABLE, RECORD_DISABLE_G0CB_DECRYPT, 1, 1) + FIELD(EXTMEM_CACHE_ENCRYPT_DECRYPT_RECORD_DISABLE, RECORD_DISABLE_DB_ENCRYPT, 0, 1) + +REG32(EXTMEM_CACHE_ENCRYPT_DECRYPT_CLK_FORCE_ON, 0x0B8) + FIELD(EXTMEM_CACHE_ENCRYPT_DECRYPT_CLK_FORCE_ON, CLK_FORCE_ON_CRYPT, 2, 1) + FIELD(EXTMEM_CACHE_ENCRYPT_DECRYPT_CLK_FORCE_ON, CLK_FORCE_ON_AUTO_CRYPT, 1, 1) + FIELD(EXTMEM_CACHE_ENCRYPT_DECRYPT_CLK_FORCE_ON, CLK_FORCE_ON_MANUAL_CRYPT, 0, 1) + +REG32(EXTMEM_CACHE_PRELOAD_INT_CTRL, 0x0BC) + FIELD(EXTMEM_CACHE_PRELOAD_INT_CTRL, ICACHE_PRELOAD_INT_CLR, 2, 1) + FIELD(EXTMEM_CACHE_PRELOAD_INT_CTRL, ICACHE_PRELOAD_INT_ENA, 1, 1) + FIELD(EXTMEM_CACHE_PRELOAD_INT_CTRL, ICACHE_PRELOAD_INT_ST, 0, 1) + +REG32(EXTMEM_CACHE_SYNC_INT_CTRL, 0x0C0) + FIELD(EXTMEM_CACHE_SYNC_INT_CTRL, ICACHE_SYNC_INT_CLR, 2, 1) + FIELD(EXTMEM_CACHE_SYNC_INT_CTRL, ICACHE_SYNC_INT_ENA, 1, 1) + FIELD(EXTMEM_CACHE_SYNC_INT_CTRL, ICACHE_SYNC_INT_ST, 0, 1) + +REG32(EXTMEM_CACHE_MMU_OWNER, 0x0C4) + FIELD(EXTMEM_CACHE_MMU_OWNER, CACHE_MMU_OWNER, 0, 4) + +REG32(EXTMEM_CACHE_CONF_MISC, 0x0C8) + FIELD(EXTMEM_CACHE_CONF_MISC, CACHE_TRACE_ENA, 2, 1) + FIELD(EXTMEM_CACHE_CONF_MISC, CACHE_IGNORE_SYNC_MMU_ENTRY_FAULT, 1, 1) + FIELD(EXTMEM_CACHE_CONF_MISC, CACHE_IGNORE_PRELOAD_MMU_ENTRY_FAULT, 0, 1) + +REG32(EXTMEM_ICACHE_FREEZE, 0x0CC) + FIELD(EXTMEM_ICACHE_FREEZE, ICACHE_FREEZE_DONE, 2, 1) + FIELD(EXTMEM_ICACHE_FREEZE, ICACHE_FREEZE_MODE, 1, 1) + FIELD(EXTMEM_ICACHE_FREEZE, ICACHE_FREEZE_ENA, 0, 1) + +REG32(EXTMEM_ICACHE_ATOMIC_OPERATE_ENA, 0x0D0) + FIELD(EXTMEM_ICACHE_ATOMIC_OPERATE_ENA, ICACHE_ATOMIC_OPERATE_ENA, 0, 1) + +REG32(EXTMEM_CACHE_REQUEST, 0x0D4) + FIELD(EXTMEM_CACHE_REQUEST, CACHE_REQUEST_BYPASS, 0, 1) + +REG32(EXTMEM_IBUS_PMS_TBL_LOCK, 0x0D8) + FIELD(EXTMEM_IBUS_PMS_TBL_LOCK, IBUS_PMS_LOCK, 0, 1) + +REG32(EXTMEM_IBUS_PMS_TBL_BOUNDARY0, 0x0DC) + FIELD(EXTMEM_IBUS_PMS_TBL_BOUNDARY0, IBUS_PMS_BOUNDARY0, 0, 12) + +REG32(EXTMEM_IBUS_PMS_TBL_BOUNDARY1, 0x0E0) + FIELD(EXTMEM_IBUS_PMS_TBL_BOUNDARY1, IBUS_PMS_BOUNDARY1, 0, 12) + +REG32(EXTMEM_IBUS_PMS_TBL_BOUNDARY2, 0x0E4) + FIELD(EXTMEM_IBUS_PMS_TBL_BOUNDARY2, IBUS_PMS_BOUNDARY2, 0, 12) + +REG32(EXTMEM_IBUS_PMS_TBL_ATTR, 0x0E8) + FIELD(EXTMEM_IBUS_PMS_TBL_ATTR, IBUS_PMS_SCT2_ATTR, 4, 4) + FIELD(EXTMEM_IBUS_PMS_TBL_ATTR, IBUS_PMS_SCT1_ATTR, 0, 4) + +REG32(EXTMEM_DBUS_PMS_TBL_LOCK, 0x0EC) + FIELD(EXTMEM_DBUS_PMS_TBL_LOCK, DBUS_PMS_LOCK, 0, 1) + +REG32(EXTMEM_DBUS_PMS_TBL_BOUNDARY0, 0x0F0) + FIELD(EXTMEM_DBUS_PMS_TBL_BOUNDARY0, DBUS_PMS_BOUNDARY0, 0, 12) + +REG32(EXTMEM_DBUS_PMS_TBL_BOUNDARY1, 0x0F4) + FIELD(EXTMEM_DBUS_PMS_TBL_BOUNDARY1, DBUS_PMS_BOUNDARY1, 0, 12) + +REG32(EXTMEM_DBUS_PMS_TBL_BOUNDARY2, 0x0F8) + FIELD(EXTMEM_DBUS_PMS_TBL_BOUNDARY2, DBUS_PMS_BOUNDARY2, 0, 12) + +REG32(EXTMEM_DBUS_PMS_TBL_ATTR, 0x0FC) + FIELD(EXTMEM_DBUS_PMS_TBL_ATTR, DBUS_PMS_SCT2_ATTR, 2, 2) + FIELD(EXTMEM_DBUS_PMS_TBL_ATTR, DBUS_PMS_SCT1_ATTR, 0, 2) + +REG32(EXTMEM_CLOCK_GATE, 0x100) + FIELD(EXTMEM_CLOCK_GATE, CLK_EN, 0, 1) + +REG32(EXTMEM_DATE, 0x3FC) + FIELD(EXTMEM_DATE, DATE, 0, 28) + diff --git a/include/hw/misc/esp32c3_jtag.h b/include/hw/misc/esp32c3_jtag.h new file mode 100644 index 000000000000..8ac6ebb58453 --- /dev/null +++ b/include/hw/misc/esp32c3_jtag.h @@ -0,0 +1,26 @@ +/* + * ESP32-C3 USB Serial JTAG emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" + +#define TYPE_ESP32C3_JTAG "misc.esp32c3.usb_serial_jtag" +#define ESP32C3_JTAG(obj) OBJECT_CHECK(ESP32C3UsbJtagState, (obj), TYPE_ESP32C3_JTAG) + +#define ESP32C3_JTAG_REGS_SIZE (0x84) + + +typedef struct ESP32C3UsbJtagState { + SysBusDevice parent_object; + MemoryRegion iomem; +} ESP32C3UsbJtagState; + diff --git a/include/hw/misc/esp32c3_reg.h b/include/hw/misc/esp32c3_reg.h new file mode 100644 index 000000000000..14d2eacfa506 --- /dev/null +++ b/include/hw/misc/esp32c3_reg.h @@ -0,0 +1,49 @@ +#pragma once + +#define DR_REG_SYSTEM_BASE 0x600c0000 +#define DR_REG_SENSITIVE_BASE 0x600c1000 +#define DR_REG_INTERRUPT_BASE 0x600c2000 +#define DR_REG_EXTMEM_BASE 0x600c4000 +#define DR_REG_MMU_TABLE 0x600c5000 +#define DR_REG_AES_BASE 0x6003a000 +#define DR_REG_SHA_BASE 0x6003b000 +#define DR_REG_RSA_BASE 0x6003c000 +#define DR_REG_HMAC_BASE 0x6003e000 +#define DR_REG_DIGITAL_SIGNATURE_BASE 0x6003d000 +#define DR_REG_GDMA_BASE 0x6003f000 +#define DR_REG_ASSIST_DEBUG_BASE 0x600ce000 +#define DR_REG_DEDICATED_GPIO_BASE 0x600cf000 +#define DR_REG_WORLD_CNTL_BASE 0x600d0000 +#define DR_REG_DPORT_END 0x600d3FFC +#define DR_REG_UART_BASE 0x60000000 +#define DR_REG_SPI1_BASE 0x60002000 +#define DR_REG_SPI0_BASE 0x60003000 +#define DR_REG_GPIO_BASE 0x60004000 +#define DR_REG_FE2_BASE 0x60005000 +#define DR_REG_FE_BASE 0x60006000 +#define DR_REG_RTCCNTL_BASE 0x60008000 +#define DR_REG_IO_MUX_BASE 0x60009000 +#define DR_REG_RTC_I2C_BASE 0x6000e000 +#define DR_REG_UART1_BASE 0x60010000 +#define DR_REG_I2C_EXT_BASE 0x60013000 +#define DR_REG_UHCI0_BASE 0x60014000 +#define DR_REG_RMT_BASE 0x60016000 +#define DR_REG_LEDC_BASE 0x60019000 +#define DR_REG_EFUSE_BASE 0x60008800 +#define DR_REG_NRX_BASE 0x6001CC00 +#define DR_REG_BB_BASE 0x6001D000 +#define DR_REG_TIMERGROUP0_BASE 0x6001F000 +#define DR_REG_TIMERGROUP1_BASE 0x60020000 +#define DR_REG_SYSTIMER_BASE 0x60023000 +#define DR_REG_SPI2_BASE 0x60024000 +#define DR_REG_SYSCON_BASE 0x60026000 +#define DR_REG_APB_CTRL_BASE 0x60026000 /* Old name for SYSCON, to be removed */ +#define DR_REG_TWAI_BASE 0x6002B000 +#define DR_REG_I2S0_BASE 0x6002D000 +#define DR_REG_APB_SARADC_BASE 0x60040000 +#define DR_REG_USB_SERIAL_JTAG_BASE 0x60043000 +#define DR_REG_AES_XTS_BASE 0x600CC000 + + +#define ESP32C3_IO_START_ADDR (DR_REG_UART_BASE) +#define ESP32C3_UART_COUNT 2 diff --git a/include/hw/misc/esp32c3_rsa.h b/include/hw/misc/esp32c3_rsa.h new file mode 100644 index 000000000000..961c55562cc8 --- /dev/null +++ b/include/hw/misc/esp32c3_rsa.h @@ -0,0 +1,88 @@ +/* + * ESP32-C3 RSA accelerator + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/esp32c3_reg.h" + + +#define TYPE_ESP32C3_RSA "misc.esp32c3.rsa" +#define ESP32C3_RSA(obj) OBJECT_CHECK(ESP32C3RsaState, (obj), TYPE_ESP32C3_RSA) + +#define ESP32C3_RSA_MEM_BLK_SIZE 384 + +typedef struct ESP32C3RsaState { + SysBusDevice parent_obj; + MemoryRegion iomem; + + uint32_t m_mem[ESP32C3_RSA_MEM_BLK_SIZE / 4]; + uint32_t z_mem[ESP32C3_RSA_MEM_BLK_SIZE / 4]; + uint32_t y_mem[ESP32C3_RSA_MEM_BLK_SIZE / 4]; + uint32_t x_mem[ESP32C3_RSA_MEM_BLK_SIZE / 4]; + + /* Configuration registers */ + uint32_t mprime_reg; + uint32_t mode_reg; + uint32_t const_time_reg; + uint32_t search_ena_reg; + uint32_t search_pos_reg; + + /* Status/Control registers */ + uint32_t int_ena; + qemu_irq irq; +} ESP32C3RsaState; + + +REG32(RSA_MEM_M_BLOCK_BASE, 0x000) + +REG32(RSA_MEM_Z_BLOCK_BASE, 0x200) + +REG32(RSA_MEM_Y_BLOCK_BASE, 0x400) + +REG32(RSA_MEM_X_BLOCK_BASE, 0x600) + +REG32(RSA_M_PRIME_REG, 0x800) + +REG32(RSA_MODE_REG, 0x804) + FIELD(RSA_MODE_REG, RSA_MODE, 0, 7) + +REG32(RSA_CLEAN_REG, 0x808) + FIELD(RSA_CLEAN_REG, RSA_CLEAN, 0, 1) + +REG32(RSA_MODEXP_START_REG, 0x80C) + FIELD(RSA_MODEXP_START_REG, RSA_MODEXP_START, 0, 1) + +REG32(RSA_MODMULT_START_REG, 0x810) + FIELD(RSA_MODMULT_START_REG, RSA_MODMULT_START, 0, 1) + +REG32(RSA_MULT_START_REG, 0x814) + FIELD(RSA_MULT_START_REG, RSA_MULT_START, 0, 1) + +REG32(RSA_IDLE_REG, 0x818) + FIELD(RSA_IDLE_REG, RSA_IDLE, 0, 1) + +REG32(RSA_CLEAR_INTERRUPT_REG, 0x81C) + FIELD(RSA_CLEAR_INTERRUPT_REG, RSA_CLEAR_INTERRUPT, 0, 1) + +REG32(RSA_CONSTANT_TIME_REG, 0x820) + FIELD(RSA_CONSTANT_TIME_REG, RSA_CONSTANT_TIME, 0, 1) + +REG32(RSA_SEARCH_ENABLE_REG, 0x824) + FIELD(RSA_SEARCH_ENABLE_REG, RSA_SEARCH_ENABLE, 0, 1) + +REG32(RSA_SEARCH_POS_REG, 0x828) + FIELD(RSA_SEARCH_POS_REG, RSA_SEARCH_POS, 0, 12) + +REG32(RSA_INTERRUPT_ENA_REG, 0x82C) + FIELD(RSA_INTERRUPT_ENA_REG, RSA_INTERRUPT_ENA, 0, 1) + +REG32(RSA_DATE_REG, 0x830) diff --git a/include/hw/misc/esp32c3_rtc_cntl.h b/include/hw/misc/esp32c3_rtc_cntl.h new file mode 100644 index 000000000000..c7e97ccead5e --- /dev/null +++ b/include/hw/misc/esp32c3_rtc_cntl.h @@ -0,0 +1,508 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" + +#include "hw/misc/esp32c3_reg.h" + +#define TYPE_ESP32C3_RTC_CNTL "misc.esp32c3.rtc_cntl" +#define ESP32C3_RTC_CNTL(obj) OBJECT_CHECK(ESP32C3RtcCntlState, (obj), TYPE_ESP32C3_RTC_CNTL) + +#define BIT_SET(reg, bit) ((reg) & BIT(bit)) +#define CLEAR_BIT(reg, bit) do { (reg) &= ~BIT(bit); } while(0) +#define SET_BIT(reg, bit) do { (reg) |= BIT(bit); } while(0) + +#define ESP32C3_RTC_CPU_RESET_GPIO "cpu-reset" + +/** + * Size of the I/O space for the RTC CTNL. + */ +#define ESP32C3_RTC_CNTL_IO_SIZE (A_RTC_CNTL_DATE + 4) + + +typedef struct ESP32C3RtcCntlState { + SysBusDevice parent_obj; + MemoryRegion iomem; + + uint32_t options0; + qemu_irq cpu_reset; + +} ESP32C3RtcCntlState; + + +typedef enum ESP32C3ResetReason { + ESP32C3_NO_MEAN = 0, + ESP32C3_POWERON_RESET = 1, /**<1, Vbat power on reset*/ + ESP32C3_RTC_SW_SYS_RESET = 3, /**<3, Software reset digital core*/ + ESP32C3_DEEPSLEEP_RESET = 5, /**<5, Deep Sleep reset digital core*/ + ESP32C3_TG0WDT_SYS_RESET = 7, /**<7, Timer Group0 Watch dog reset digital core*/ + ESP32C3_TG1WDT_SYS_RESET = 8, /**<8, Timer Group1 Watch dog reset digital core*/ + ESP32C3_RTCWDT_SYS_RESET = 9, /**<9, RTC Watch dog Reset digital core*/ + ESP32C3_INTRUSION_RESET = 10, /**<10, Instrusion tested to reset CPU*/ + ESP32C3_TG0WDT_CPU_RESET = 11, /**<11, Time Group0 reset CPU*/ + ESP32C3_RTC_SW_CPU_RESET = 12, /**<12, Software reset CPU*/ + ESP32C3_RTCWDT_CPU_RESET = 13, /**<13, RTC Watch dog Reset CPU*/ + ESP32C3_RTCWDT_BROWN_OUT_RESET = 15, /**<15, Reset when the vdd voltage is not stable*/ + ESP32C3_RTCWDT_RTC_RESET = 16, /**<16, RTC Watch dog reset digital core and rtc module*/ + ESP32C3_TG1WDT_CPU_RESET = 17, /**<17, Time Group1 reset CPU*/ + ESP32C3_SUPER_WDT_RESET = 18, /**<18, super watchdog reset digital core and rtc module*/ + ESP32C3_GLITCH_RTC_RESET = 19, /**<19, glitch reset digital core and rtc module*/ + ESP32C3_EFUSE_RESET = 20, /**<20, efuse reset digital core*/ + ESP32C3_USB_UART_CHIP_RESET = 21, /**<21, usb uart reset digital core and rtc module */ + ESP32C3_USB_JTAG_CHIP_RESET = 22, /**<22, usb jtag reset digital core and rtc module*/ + ESP32C3_POWER_GLITCH_RESET = 23, /**<23, power glitch reset digital core and rtc module*/ +} ESP32C3ResetReason; + +REG32(RTC_CNTL_RTC_OPTIONS0, 0x0000) + FIELD(RTC_CNTL_RTC_OPTIONS0, SW_SYS_RST, 31, 1) + FIELD(RTC_CNTL_RTC_OPTIONS0, DG_WRAP_FORCE_NORST, 30, 1) + FIELD(RTC_CNTL_RTC_OPTIONS0, DG_WRAP_FORCE_RST, 29, 1) + FIELD(RTC_CNTL_RTC_OPTIONS0, XTL_FORCE_PU, 13, 1) + FIELD(RTC_CNTL_RTC_OPTIONS0, XTL_FORCE_PD, 12, 1) + FIELD(RTC_CNTL_RTC_OPTIONS0, BBPLL_FORCE_PU, 11, 1) + FIELD(RTC_CNTL_RTC_OPTIONS0, BBPLL_FORCE_PD, 10, 1) + FIELD(RTC_CNTL_RTC_OPTIONS0, BBPLL_I2C_FORCE_PU, 9, 1) + FIELD(RTC_CNTL_RTC_OPTIONS0, BBPLL_I2C_FORCE_PD, 8, 1) + FIELD(RTC_CNTL_RTC_OPTIONS0, BB_I2C_FORCE_PU, 7, 1) + FIELD(RTC_CNTL_RTC_OPTIONS0, BB_I2C_FORCE_PD, 6, 1) + FIELD(RTC_CNTL_RTC_OPTIONS0, SW_PROCPU_RST, 5, 1) + FIELD(RTC_CNTL_RTC_OPTIONS0, SW_APPCPU_RST, 4, 1) + FIELD(RTC_CNTL_RTC_OPTIONS0, SW_STALL_PROCPU_C0, 2, 2) + +REG32(RTC_CNTL_RTC_SLP_TIMER0, 0x0004) + FIELD(RTC_CNTL_RTC_SLP_TIMER0, SLP_VAL_LO, 0, 32) + +REG32(RTC_CNTL_RTC_SLP_TIMER1, 0x0008) + FIELD(RTC_CNTL_RTC_SLP_TIMER1, RTC_MAIN_TIMER_ALARM_EN, 16, 1) + FIELD(RTC_CNTL_RTC_SLP_TIMER1, SLP_VAL_HI, 0, 16) + +REG32(RTC_CNTL_RTC_TIME_UPDATE, 0x000C) + FIELD(RTC_CNTL_RTC_TIME_UPDATE, RTC_TIME_UPDATE, 31, 1) + FIELD(RTC_CNTL_RTC_TIME_UPDATE, TIMER_SYS_RST, 29, 1) + FIELD(RTC_CNTL_RTC_TIME_UPDATE, TIMER_XTL_OFF, 28, 1) + FIELD(RTC_CNTL_RTC_TIME_UPDATE, TIMER_SYS_STALL, 27, 1) + +REG32(RTC_CNTL_RTC_TIME_LOW0, 0x0010) + FIELD(RTC_CNTL_RTC_TIME_LOW0, RTC_TIMER_VALUE0_LOW, 0, 32) + +REG32(RTC_CNTL_RTC_TIME_HIGH0, 0x0014) + FIELD(RTC_CNTL_RTC_TIME_HIGH0, RTC_TIMER_VALUE0_HIGH, 0, 16) + +REG32(RTC_CNTL_RTC_STATE0, 0x0018) + FIELD(RTC_CNTL_RTC_STATE0, SLEEP_EN, 31, 1) + FIELD(RTC_CNTL_RTC_STATE0, SLP_REJECT, 30, 1) + FIELD(RTC_CNTL_RTC_STATE0, SLP_WAKEUP, 29, 1) + FIELD(RTC_CNTL_RTC_STATE0, SDIO_ACTIVE_IND, 28, 1) + FIELD(RTC_CNTL_RTC_STATE0, APB2RTC_BRIDGE_SEL, 22, 1) + FIELD(RTC_CNTL_RTC_STATE0, RTC_SLP_REJECT_CAUSE_CLR, 1, 1) + FIELD(RTC_CNTL_RTC_STATE0, RTC_SW_CPU_INT, 0, 1) + +REG32(RTC_CNTL_RTC_TIMER1, 0x001C) + FIELD(RTC_CNTL_RTC_TIMER1, PLL_BUF_WAIT, 24, 8) + FIELD(RTC_CNTL_RTC_TIMER1, XTL_BUF_WAIT, 14, 10) + FIELD(RTC_CNTL_RTC_TIMER1, CK8M_WAIT, 6, 8) + FIELD(RTC_CNTL_RTC_TIMER1, CPU_STALL_WAIT, 1, 5) + FIELD(RTC_CNTL_RTC_TIMER1, CPU_STALL_EN, 0, 1) + +REG32(RTC_CNTL_RTC_TIMER2, 0x0020) + FIELD(RTC_CNTL_RTC_TIMER2, MIN_TIME_CK8M_OFF, 24, 8) + +REG32(RTC_CNTL_RTC_TIMER3, 0x0024) + +REG32(RTC_CNTL_RTC_TIMER4, 0x0028) + +REG32(RTC_CNTL_RTC_TIMER5, 0x002C) + FIELD(RTC_CNTL_RTC_TIMER5, MIN_SLP_VAL, 8, 8) + +REG32(RTC_CNTL_RTC_TIMER6, 0x0030) + +REG32(RTC_CNTL_RTC_ANA_CONF, 0x0034) + FIELD(RTC_CNTL_RTC_ANA_CONF, PLL_I2C_PU, 31, 1) + FIELD(RTC_CNTL_RTC_ANA_CONF, CKGEN_I2C_PU, 30, 1) + FIELD(RTC_CNTL_RTC_ANA_CONF, RFRX_PBUS_PU, 28, 1) + FIELD(RTC_CNTL_RTC_ANA_CONF, TXRF_I2C_PU, 27, 1) + FIELD(RTC_CNTL_RTC_ANA_CONF, PVTMON_PU, 26, 1) + FIELD(RTC_CNTL_RTC_ANA_CONF, PLLA_FORCE_PU, 24, 1) + FIELD(RTC_CNTL_RTC_ANA_CONF, PLLA_FORCE_PD, 23, 1) + FIELD(RTC_CNTL_RTC_ANA_CONF, SAR_I2C_PU, 22, 1) + FIELD(RTC_CNTL_RTC_ANA_CONF, GLITCH_RST_EN, 20, 1) + FIELD(RTC_CNTL_RTC_ANA_CONF, RESET_POR_FORCE_PU, 19, 1) + FIELD(RTC_CNTL_RTC_ANA_CONF, RESET_POR_FORCE_PD, 18, 1) + +REG32(RTC_CNTL_RTC_RESET_STATE, 0x0038) + FIELD(RTC_CNTL_RTC_RESET_STATE, RTC_DRESET_MASK_PROCPU, 25, 1) + FIELD(RTC_CNTL_RTC_RESET_STATE, RTC_DRESET_MASK_APPCPU, 24, 1) + FIELD(RTC_CNTL_RTC_RESET_STATE, JTAG_RESET_FLAG_CLR_APPCPU, 23, 1) + FIELD(RTC_CNTL_RTC_RESET_STATE, JTAG_RESET_FLAG_CLR_PROCPU, 22, 1) + FIELD(RTC_CNTL_RTC_RESET_STATE, JTAG_RESET_FLAG_APPCPU, 21, 1) + FIELD(RTC_CNTL_RTC_RESET_STATE, JTAG_RESET_FLAG_PROCPU, 20, 1) + FIELD(RTC_CNTL_RTC_RESET_STATE, OCD_HALT_ON_RESET_PROCPU, 19, 1) + FIELD(RTC_CNTL_RTC_RESET_STATE, OCD_HALT_ON_RESET_APPCPU, 18, 1) + FIELD(RTC_CNTL_RTC_RESET_STATE, ALL_RESET_FLAG_CLR_APPCPU, 17, 1) + FIELD(RTC_CNTL_RTC_RESET_STATE, ALL_RESET_FLAG_CLR_PROCPU, 16, 1) + FIELD(RTC_CNTL_RTC_RESET_STATE, ALL_RESET_FLAG_APPCPU, 15, 1) + FIELD(RTC_CNTL_RTC_RESET_STATE, ALL_RESET_FLAG_PROCPU, 14, 1) + FIELD(RTC_CNTL_RTC_RESET_STATE, STAT_VECTOR_SEL_PROCPU, 13, 1) + FIELD(RTC_CNTL_RTC_RESET_STATE, STAT_VECTOR_SEL_APPCPU, 12, 1) + FIELD(RTC_CNTL_RTC_RESET_STATE, RESET_CAUSE_PROCPU, 0, 6) + +REG32(RTC_CNTL_RTC_WAKEUP_STATE, 0x003C) + FIELD(RTC_CNTL_RTC_WAKEUP_STATE, RTC_WAKEUP_ENA, 15, 17) + +REG32(RTC_CNTL_INT_ENA_RTC, 0x0040) + FIELD(RTC_CNTL_INT_ENA_RTC, RTC_BBPLL_CAL_INT_ENA, 20, 1) + FIELD(RTC_CNTL_INT_ENA_RTC, RTC_GLITCH_DET_INT_ENA, 19, 1) + FIELD(RTC_CNTL_INT_ENA_RTC, RTC_XTAL32K_DEAD_INT_ENA, 16, 1) + FIELD(RTC_CNTL_INT_ENA_RTC, RTC_SWD_INT_ENA, 15, 1) + FIELD(RTC_CNTL_INT_ENA_RTC, RTC_MAIN_TIMER_INT_ENA, 10, 1) + FIELD(RTC_CNTL_INT_ENA_RTC, RTC_BROWN_OUT_INT_ENA, 9, 1) + FIELD(RTC_CNTL_INT_ENA_RTC, RTC_WDT_INT_ENA, 3, 1) + FIELD(RTC_CNTL_INT_ENA_RTC, SLP_REJECT_INT_ENA, 1, 1) + FIELD(RTC_CNTL_INT_ENA_RTC, SLP_WAKEUP_INT_ENA, 0, 1) + +REG32(RTC_CNTL_INT_RAW_RTC, 0x0044) + FIELD(RTC_CNTL_INT_RAW_RTC, RTC_BBPLL_CAL_INT_RAW, 20, 1) + FIELD(RTC_CNTL_INT_RAW_RTC, RTC_GLITCH_DET_INT_RAW, 19, 1) + FIELD(RTC_CNTL_INT_RAW_RTC, RTC_XTAL32K_DEAD_INT_RAW, 16, 1) + FIELD(RTC_CNTL_INT_RAW_RTC, RTC_SWD_INT_RAW, 15, 1) + FIELD(RTC_CNTL_INT_RAW_RTC, RTC_MAIN_TIMER_INT_RAW, 10, 1) + FIELD(RTC_CNTL_INT_RAW_RTC, RTC_BROWN_OUT_INT_RAW, 9, 1) + FIELD(RTC_CNTL_INT_RAW_RTC, RTC_WDT_INT_RAW, 3, 1) + FIELD(RTC_CNTL_INT_RAW_RTC, SLP_REJECT_INT_RAW, 1, 1) + FIELD(RTC_CNTL_INT_RAW_RTC, SLP_WAKEUP_INT_RAW, 0, 1) + +REG32(RTC_CNTL_INT_ST_RTC, 0x0048) + FIELD(RTC_CNTL_INT_ST_RTC, RTC_BBPLL_CAL_INT_ST, 20, 1) + FIELD(RTC_CNTL_INT_ST_RTC, RTC_GLITCH_DET_INT_ST, 19, 1) + FIELD(RTC_CNTL_INT_ST_RTC, RTC_XTAL32K_DEAD_INT_ST, 16, 1) + FIELD(RTC_CNTL_INT_ST_RTC, RTC_SWD_INT_ST, 15, 1) + FIELD(RTC_CNTL_INT_ST_RTC, RTC_MAIN_TIMER_INT_ST, 10, 1) + FIELD(RTC_CNTL_INT_ST_RTC, RTC_BROWN_OUT_INT_ST, 9, 1) + FIELD(RTC_CNTL_INT_ST_RTC, RTC_WDT_INT_ST, 3, 1) + FIELD(RTC_CNTL_INT_ST_RTC, SLP_REJECT_INT_ST, 1, 1) + FIELD(RTC_CNTL_INT_ST_RTC, SLP_WAKEUP_INT_ST, 0, 1) + +REG32(RTC_CNTL_INT_CLR_RTC, 0x004C) + FIELD(RTC_CNTL_INT_CLR_RTC, RTC_BBPLL_CAL_INT_CLR, 20, 1) + FIELD(RTC_CNTL_INT_CLR_RTC, RTC_GLITCH_DET_INT_CLR, 19, 1) + FIELD(RTC_CNTL_INT_CLR_RTC, RTC_XTAL32K_DEAD_INT_CLR, 16, 1) + FIELD(RTC_CNTL_INT_CLR_RTC, RTC_SWD_INT_CLR, 15, 1) + FIELD(RTC_CNTL_INT_CLR_RTC, RTC_MAIN_TIMER_INT_CLR, 10, 1) + FIELD(RTC_CNTL_INT_CLR_RTC, RTC_BROWN_OUT_INT_CLR, 9, 1) + FIELD(RTC_CNTL_INT_CLR_RTC, RTC_WDT_INT_CLR, 3, 1) + FIELD(RTC_CNTL_INT_CLR_RTC, SLP_REJECT_INT_CLR, 1, 1) + FIELD(RTC_CNTL_INT_CLR_RTC, SLP_WAKEUP_INT_CLR, 0, 1) + +REG32(RTC_CNTL_RTC_STORE0, 0x0050) + FIELD(RTC_CNTL_RTC_STORE0, RTC_SCRATCH0, 0, 32) + +REG32(RTC_CNTL_RTC_STORE1, 0x0054) + FIELD(RTC_CNTL_RTC_STORE1, RTC_SCRATCH1, 0, 32) + +REG32(RTC_CNTL_RTC_STORE2, 0x0058) + FIELD(RTC_CNTL_RTC_STORE2, RTC_SCRATCH2, 0, 32) + +REG32(RTC_CNTL_RTC_STORE3, 0x005C) + FIELD(RTC_CNTL_RTC_STORE3, RTC_SCRATCH3, 0, 32) + +REG32(RTC_CNTL_RTC_EXT_XTL_CONF, 0x0060) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, XTL_EXT_CTR_EN, 31, 1) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, XTL_EXT_CTR_LV, 30, 1) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, RTC_XTAL32K_GPIO_SEL, 23, 1) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, RTC_WDT_STATE, 20, 3) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, DAC_XTAL_32K, 17, 3) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, XPD_XTAL_32K, 16, 1) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, DRES_XTAL_32K, 13, 3) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, DGM_XTAL_32K, 10, 3) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, DBUF_XTAL_32K, 9, 1) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, ENCKINIT_XTAL_32K, 8, 1) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, XTAL32K_XPD_FORCE, 7, 1) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, XTAL32K_AUTO_RETURN, 6, 1) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, XTAL32K_AUTO_RESTART, 5, 1) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, XTAL32K_AUTO_BACKUP, 4, 1) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, XTAL32K_EXT_CLK_FO, 3, 1) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, XTAL32K_WDT_RESET, 2, 1) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, XTAL32K_WDT_CLK_FO, 1, 1) + FIELD(RTC_CNTL_RTC_EXT_XTL_CONF, XTAL32K_WDT_EN, 0, 1) + +REG32(RTC_CNTL_RTC_EXT_WAKEUP_CONF, 0x0064) + FIELD(RTC_CNTL_RTC_EXT_WAKEUP_CONF, GPIO_WAKEUP_FILTER, 31, 1) + +REG32(RTC_CNTL_RTC_SLP_REJECT_CONF, 0x0068) + FIELD(RTC_CNTL_RTC_SLP_REJECT_CONF, DEEP_SLP_REJECT_EN, 31, 1) + FIELD(RTC_CNTL_RTC_SLP_REJECT_CONF, LIGHT_SLP_REJECT_EN, 30, 1) + FIELD(RTC_CNTL_RTC_SLP_REJECT_CONF, RTC_SLEEP_REJECT_ENA, 12, 17) + +REG32(RTC_CNTL_RTC_CPU_PERIOD_CONF, 0x006C) + FIELD(RTC_CNTL_RTC_CPU_PERIOD_CONF, RTC_CPUPERIOD_SEL, 30, 2) + FIELD(RTC_CNTL_RTC_CPU_PERIOD_CONF, RTC_CPUSEL_CONF, 29, 1) + +REG32(RTC_CNTL_RTC_CLK_CONF, 0x0070) + FIELD(RTC_CNTL_RTC_CLK_CONF, ANA_CLK_RTC_SEL, 30, 2) + FIELD(RTC_CNTL_RTC_CLK_CONF, FAST_CLK_RTC_SEL, 29, 1) + FIELD(RTC_CNTL_RTC_CLK_CONF, XTAL_GLOBAL_FORCE_NOGATING, 28, 1) + FIELD(RTC_CNTL_RTC_CLK_CONF, XTAL_GLOBAL_FORCE_GATING, 27, 1) + FIELD(RTC_CNTL_RTC_CLK_CONF, CK8M_FORCE_PU, 26, 1) + FIELD(RTC_CNTL_RTC_CLK_CONF, CK8M_FORCE_PD, 25, 1) + FIELD(RTC_CNTL_RTC_CLK_CONF, CK8M_DFREQ, 17, 8) + FIELD(RTC_CNTL_RTC_CLK_CONF, CK8M_FORCE_NOGATING, 16, 1) + FIELD(RTC_CNTL_RTC_CLK_CONF, XTAL_FORCE_NOGATING, 15, 1) + FIELD(RTC_CNTL_RTC_CLK_CONF, CK8M_DIV_SEL, 12, 3) + FIELD(RTC_CNTL_RTC_CLK_CONF, DIG_CLK8M_EN, 10, 1) + FIELD(RTC_CNTL_RTC_CLK_CONF, DIG_CLK8M_D256_EN, 9, 1) + FIELD(RTC_CNTL_RTC_CLK_CONF, DIG_XTAL32K_EN, 8, 1) + FIELD(RTC_CNTL_RTC_CLK_CONF, ENB_CK8M_DIV, 7, 1) + FIELD(RTC_CNTL_RTC_CLK_CONF, ENB_CK8M, 6, 1) + FIELD(RTC_CNTL_RTC_CLK_CONF, CK8M_DIV, 4, 2) + FIELD(RTC_CNTL_RTC_CLK_CONF, CK8M_DIV_SEL_VLD, 3, 1) + FIELD(RTC_CNTL_RTC_CLK_CONF, EFUSE_CLK_FORCE_NOGATING, 2, 1) + FIELD(RTC_CNTL_RTC_CLK_CONF, EFUSE_CLK_FORCE_GATING, 1, 1) + +REG32(RTC_CNTL_RTC_SLOW_CLK_CONF, 0x0074) + FIELD(RTC_CNTL_RTC_SLOW_CLK_CONF, RTC_SLOW_CLK_NEXT_EDGE, 31, 1) + FIELD(RTC_CNTL_RTC_SLOW_CLK_CONF, RTC_ANA_CLK_DIV, 23, 8) + FIELD(RTC_CNTL_RTC_SLOW_CLK_CONF, RTC_ANA_CLK_DIV_VLD, 22, 1) + +REG32(RTC_CNTL_RTC_SDIO_CONF, 0x0078) + +REG32(RTC_CNTL_RTC_BIAS_CONF, 0x007C) + +REG32(RTC_CNTL_RTC, 0x0080) + FIELD(RTC_CNTL_RTC, RTC_REGULATOR_FORCE_PU, 31, 1) + FIELD(RTC_CNTL_RTC, RTC_REGULATOR_FORCE_PD, 30, 1) + FIELD(RTC_CNTL_RTC, RTC_DBOOST_FORCE_PU, 29, 1) + FIELD(RTC_CNTL_RTC, RTC_DBOOST_FORCE_PD, 28, 1) + FIELD(RTC_CNTL_RTC, SCK_DCAP, 14, 8) + FIELD(RTC_CNTL_RTC, DIG_REG_CAL_EN, 7, 1) + +REG32(RTC_CNTL_RTC_PWC, 0x0084) + FIELD(RTC_CNTL_RTC_PWC, RTC_PAD_FORCE_HOLD, 21, 1) + +REG32(RTC_CNTL_DIG_PWC, 0x0088) + FIELD(RTC_CNTL_DIG_PWC, DG_WRAP_PD_EN, 31, 1) + FIELD(RTC_CNTL_DIG_PWC, WIFI_PD_EN, 30, 1) + FIELD(RTC_CNTL_DIG_PWC, CPU_TOP_PD_EN, 29, 1) + FIELD(RTC_CNTL_DIG_PWC, DG_PERI_PD_EN, 28, 1) + FIELD(RTC_CNTL_DIG_PWC, BT_PD_EN, 27, 1) + FIELD(RTC_CNTL_DIG_PWC, CPU_TOP_FORCE_PU, 22, 1) + FIELD(RTC_CNTL_DIG_PWC, CPU_TOP_FORCE_PD, 21, 1) + FIELD(RTC_CNTL_DIG_PWC, DG_WRAP_FORCE_PU, 20, 1) + FIELD(RTC_CNTL_DIG_PWC, DG_WRAP_FORCE_PD, 19, 1) + FIELD(RTC_CNTL_DIG_PWC, WIFI_FORCE_PU, 18, 1) + FIELD(RTC_CNTL_DIG_PWC, WIFI_FORCE_PD, 17, 1) + FIELD(RTC_CNTL_DIG_PWC, RTC_FASTMEM_FORCE_LPU, 16, 1) + FIELD(RTC_CNTL_DIG_PWC, RTC_FASTMEM_FORCE_LPD, 15, 1) + FIELD(RTC_CNTL_DIG_PWC, DG_PERI_FORCE_PU, 14, 1) + FIELD(RTC_CNTL_DIG_PWC, DG_PERI_FORCE_PD, 13, 1) + FIELD(RTC_CNTL_DIG_PWC, BT_FORCE_PU, 12, 1) + FIELD(RTC_CNTL_DIG_PWC, BT_FORCE_PD, 11, 1) + FIELD(RTC_CNTL_DIG_PWC, LSLP_MEM_FORCE_PU, 4, 1) + FIELD(RTC_CNTL_DIG_PWC, LSLP_MEM_FORCE_PD, 3, 1) + FIELD(RTC_CNTL_DIG_PWC, VDD_SPI_PWR_FORCE, 2, 1) + FIELD(RTC_CNTL_DIG_PWC, VDD_SPI_PWR_DRV, 0, 2) + +REG32(RTC_CNTL_DIG_ISO, 0x008C) + FIELD(RTC_CNTL_DIG_ISO, DG_WRAP_FORCE_NOISO, 31, 1) + FIELD(RTC_CNTL_DIG_ISO, DG_WRAP_FORCE_ISO, 30, 1) + FIELD(RTC_CNTL_DIG_ISO, WIFI_FORCE_NOISO, 29, 1) + FIELD(RTC_CNTL_DIG_ISO, WIFI_FORCE_ISO, 28, 1) + FIELD(RTC_CNTL_DIG_ISO, CPU_TOP_FORCE_NOISO, 27, 1) + FIELD(RTC_CNTL_DIG_ISO, CPU_TOP_FORCE_ISO, 26, 1) + FIELD(RTC_CNTL_DIG_ISO, DG_PERI_FORCE_NOISO, 25, 1) + FIELD(RTC_CNTL_DIG_ISO, DG_PERI_FORCE_ISO, 24, 1) + FIELD(RTC_CNTL_DIG_ISO, BT_FORCE_NOISO, 23, 1) + FIELD(RTC_CNTL_DIG_ISO, BT_FORCE_ISO, 22, 1) + FIELD(RTC_CNTL_DIG_ISO, DG_PAD_FORCE_HOLD, 15, 1) + FIELD(RTC_CNTL_DIG_ISO, DG_PAD_FORCE_UNHOLD, 14, 1) + FIELD(RTC_CNTL_DIG_ISO, DG_PAD_FORCE_ISO, 13, 1) + FIELD(RTC_CNTL_DIG_ISO, DG_PAD_FORCE_NOISO, 12, 1) + FIELD(RTC_CNTL_DIG_ISO, DG_PAD_AUTOHOLD_EN, 11, 1) + FIELD(RTC_CNTL_DIG_ISO, CLR_DG_PAD_AUTOHOLD, 10, 1) + FIELD(RTC_CNTL_DIG_ISO, DG_PAD_AUTOHOLD, 9, 1) + +REG32(RTC_CNTL_RTC_WDTCONFIG0, 0x0090) + FIELD(RTC_CNTL_RTC_WDTCONFIG0, WDT_EN, 31, 1) + FIELD(RTC_CNTL_RTC_WDTCONFIG0, WDT_STG0, 28, 3) + FIELD(RTC_CNTL_RTC_WDTCONFIG0, WDT_STG1, 25, 3) + FIELD(RTC_CNTL_RTC_WDTCONFIG0, WDT_STG2, 22, 3) + FIELD(RTC_CNTL_RTC_WDTCONFIG0, WDT_STG3, 19, 3) + FIELD(RTC_CNTL_RTC_WDTCONFIG0, WDT_CPU_RESET_LENGTH, 16, 3) + FIELD(RTC_CNTL_RTC_WDTCONFIG0, WDT_SYS_RESET_LENGTH, 13, 3) + FIELD(RTC_CNTL_RTC_WDTCONFIG0, WDT_FLASHBOOT_MOD_EN, 12, 1) + FIELD(RTC_CNTL_RTC_WDTCONFIG0, WDT_PROCPU_RESET_EN, 11, 1) + FIELD(RTC_CNTL_RTC_WDTCONFIG0, WDT_APPCPU_RESET_EN, 10, 1) + FIELD(RTC_CNTL_RTC_WDTCONFIG0, WDT_PAUSE_IN_SLP, 9, 1) + +REG32(RTC_CNTL_RTC_WDTCONFIG1, 0x0094) + FIELD(RTC_CNTL_RTC_WDTCONFIG1, WDT_STG0_HOLD, 0, 32) + +REG32(RTC_CNTL_RTC_WDTCONFIG2, 0x0098) + FIELD(RTC_CNTL_RTC_WDTCONFIG2, WDT_STG1_HOLD, 0, 32) + +REG32(RTC_CNTL_RTC_WDTCONFIG3, 0x009C) + FIELD(RTC_CNTL_RTC_WDTCONFIG3, WDT_STG2_HOLD, 0, 32) + +REG32(RTC_CNTL_RTC_WDTCONFIG4, 0x00A0) + FIELD(RTC_CNTL_RTC_WDTCONFIG4, WDT_STG3_HOLD, 0, 32) + +REG32(RTC_CNTL_RTC_WDTFEED, 0x00A4) + FIELD(RTC_CNTL_RTC_WDTFEED, RTC_WDT_FEED, 31, 1) + +REG32(RTC_CNTL_RTC_WDTWPROTECT, 0x00A8) + FIELD(RTC_CNTL_RTC_WDTWPROTECT, WDT_WKEY, 0, 32) + +REG32(RTC_CNTL_RTC_SWD_CONF, 0x00AC) + FIELD(RTC_CNTL_RTC_SWD_CONF, SWD_AUTO_FEED_EN, 31, 1) + FIELD(RTC_CNTL_RTC_SWD_CONF, SWD_DISABLE, 30, 1) + FIELD(RTC_CNTL_RTC_SWD_CONF, SWD_FEED, 29, 1) + FIELD(RTC_CNTL_RTC_SWD_CONF, SWD_RST_FLAG_CLR, 28, 1) + FIELD(RTC_CNTL_RTC_SWD_CONF, SWD_SIGNAL_WIDTH, 18, 10) + FIELD(RTC_CNTL_RTC_SWD_CONF, SWD_BYPASS_RST, 17, 1) + FIELD(RTC_CNTL_RTC_SWD_CONF, SWD_FEED_INT, 1, 1) + FIELD(RTC_CNTL_RTC_SWD_CONF, SWD_RESET_FLAG, 0, 1) + +REG32(RTC_CNTL_RTC_SWD_WPROTECT, 0x00B0) + FIELD(RTC_CNTL_RTC_SWD_WPROTECT, SWD_WKEY, 0, 32) + +REG32(RTC_CNTL_RTC_SW_CPU_STALL, 0x00B4) + FIELD(RTC_CNTL_RTC_SW_CPU_STALL, SW_STALL_PROCPU_C1, 26, 6) + FIELD(RTC_CNTL_RTC_SW_CPU_STALL, SW_STALL_APPCPU_C1, 20, 6) + +REG32(RTC_CNTL_RTC_STORE4, 0x00B8) + FIELD(RTC_CNTL_RTC_STORE4, RTC_SCRATCH4, 0, 32) + +REG32(RTC_CNTL_RTC_STORE5, 0x00BC) + FIELD(RTC_CNTL_RTC_STORE5, RTC_SCRATCH5, 0, 32) + +REG32(RTC_CNTL_RTC_STORE6, 0x00C0) + FIELD(RTC_CNTL_RTC_STORE6, RTC_SCRATCH6, 0, 32) + +REG32(RTC_CNTL_RTC_STORE7, 0x00C4) + FIELD(RTC_CNTL_RTC_STORE7, RTC_SCRATCH7, 0, 32) + +REG32(RTC_CNTL_RTC_LOW_POWER_ST, 0x00C8) + FIELD(RTC_CNTL_RTC_LOW_POWER_ST, RTC_RDY_FOR_WAKEUP, 19, 1) + +REG32(RTC_CNTL_RTC_DIAG0, 0x00CC) + +REG32(RTC_CNTL_RTC_PAD_HOLD, 0x00D0) + FIELD(RTC_CNTL_RTC_PAD_HOLD, RTC_GPIO_PIN5_HOLD, 5, 1) + FIELD(RTC_CNTL_RTC_PAD_HOLD, RTC_GPIO_PIN4_HOLD, 4, 1) + FIELD(RTC_CNTL_RTC_PAD_HOLD, RTC_GPIO_PIN3_HOLD, 3, 1) + FIELD(RTC_CNTL_RTC_PAD_HOLD, RTC_GPIO_PIN2_HOLD, 2, 1) + FIELD(RTC_CNTL_RTC_PAD_HOLD, RTC_GPIO_PIN1_HOLD, 1, 1) + FIELD(RTC_CNTL_RTC_PAD_HOLD, RTC_GPIO_PIN0_HOLD, 0, 1) + +REG32(RTC_CNTL_DIG_PAD_HOLD, 0x00D4) + FIELD(RTC_CNTL_DIG_PAD_HOLD, DIG_PAD_HOLD, 0, 32) + +REG32(RTC_CNTL_RTC_BROWN_OUT, 0x00D8) + FIELD(RTC_CNTL_RTC_BROWN_OUT, RTC_BROWN_OUT_DET, 31, 1) + FIELD(RTC_CNTL_RTC_BROWN_OUT, BROWN_OUT_ENA, 30, 1) + FIELD(RTC_CNTL_RTC_BROWN_OUT, BROWN_OUT_CNT_CLR, 29, 1) + FIELD(RTC_CNTL_RTC_BROWN_OUT, BROWN_OUT_ANA_RST_EN, 28, 1) + FIELD(RTC_CNTL_RTC_BROWN_OUT, BROWN_OUT_RST_SEL, 27, 1) + FIELD(RTC_CNTL_RTC_BROWN_OUT, BROWN_OUT_RST_ENA, 26, 1) + FIELD(RTC_CNTL_RTC_BROWN_OUT, BROWN_OUT_RST_WAIT, 16, 10) + FIELD(RTC_CNTL_RTC_BROWN_OUT, BROWN_OUT_PD_RF_ENA, 15, 1) + FIELD(RTC_CNTL_RTC_BROWN_OUT, BROWN_OUT_CLOSE_FLASH_ENA, 14, 1) + +REG32(RTC_CNTL_RTC_TIME_LOW1, 0x00DC) + FIELD(RTC_CNTL_RTC_TIME_LOW1, RTC_TIMER_VALUE1_LOW, 0, 32) + +REG32(RTC_CNTL_RTC_TIME_HIGH1, 0x00E0) + FIELD(RTC_CNTL_RTC_TIME_HIGH1, RTC_TIMER_VALUE1_HIGH, 0, 16) + +REG32(RTC_CNTL_RTC_XTAL32K_CLK_FACTOR, 0x00E4) + FIELD(RTC_CNTL_RTC_XTAL32K_CLK_FACTOR, XTAL32K_CLK_FACTOR, 0, 32) + +REG32(RTC_CNTL_RTC_XTAL32K_CONF, 0x00E8) + FIELD(RTC_CNTL_RTC_XTAL32K_CONF, XTAL32K_STABLE_THRES, 28, 4) + FIELD(RTC_CNTL_RTC_XTAL32K_CONF, XTAL32K_WDT_TIMEOUT, 20, 8) + FIELD(RTC_CNTL_RTC_XTAL32K_CONF, XTAL32K_RESTART_WAIT, 4, 16) + FIELD(RTC_CNTL_RTC_XTAL32K_CONF, XTAL32K_RETURN_WAIT, 0, 4) + +REG32(RTC_CNTL_RTC_USB_CONF, 0x00EC) + FIELD(RTC_CNTL_RTC_USB_CONF, IO_MUX_RESET_DISABLE, 18, 1) + +REG32(RTC_CNTL_RTC_SLP_REJECT_CAUSE, 0x00F0) + FIELD(RTC_CNTL_RTC_SLP_REJECT_CAUSE, REJECT_CAUSE, 0, 18) + +REG32(RTC_CNTL_RTC_OPTION1, 0x00F4) + FIELD(RTC_CNTL_RTC_OPTION1, FORCE_DOWNLOAD_BOOT, 0, 1) + +REG32(RTC_CNTL_RTC_SLP_WAKEUP_CAUSE, 0x00F8) + FIELD(RTC_CNTL_RTC_SLP_WAKEUP_CAUSE, WAKEUP_CAUSE, 0, 17) + +REG32(RTC_CNTL_RTC_ULP_CP_TIMER_1, 0x00FC) + FIELD(RTC_CNTL_RTC_ULP_CP_TIMER_1, ULP_CP_TIMER_SLP_CYCLE, 8, 24) + +REG32(RTC_CNTL_INT_ENA_RTC_W1TS, 0x0100) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TS, RTC_BBPLL_CAL_INT_ENA_W1TS, 20, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TS, RTC_GLITCH_DET_INT_ENA_W1TS, 19, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TS, RTC_XTAL32K_DEAD_INT_ENA_W1TS, 16, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TS, RTC_SWD_INT_ENA_W1TS, 15, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TS, RTC_MAIN_TIMER_INT_ENA_W1TS, 10, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TS, RTC_BROWN_OUT_INT_ENA_W1TS, 9, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TS, RTC_WDT_INT_ENA_W1TS, 3, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TS, SLP_REJECT_INT_ENA_W1TS, 1, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TS, SLP_WAKEUP_INT_ENA_W1TS, 0, 1) + +REG32(RTC_CNTL_INT_ENA_RTC_W1TC, 0x0104) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TC, RTC_BBPLL_CAL_INT_ENA_W1TC, 20, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TC, RTC_GLITCH_DET_INT_ENA_W1TC, 19, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TC, RTC_XTAL32K_DEAD_INT_ENA_W1TC, 16, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TC, RTC_SWD_INT_ENA_W1TC, 15, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TC, RTC_MAIN_TIMER_INT_ENA_W1TC, 10, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TC, RTC_BROWN_OUT_INT_ENA_W1TC, 9, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TC, RTC_WDT_INT_ENA_W1TC, 3, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TC, SLP_REJECT_INT_ENA_W1TC, 1, 1) + FIELD(RTC_CNTL_INT_ENA_RTC_W1TC, SLP_WAKEUP_INT_ENA_W1TC, 0, 1) + +REG32(RTC_CNTL_RTC_CNTL_RETENTION_CTRL, 0x0108) + FIELD(RTC_CNTL_RTC_CNTL_RETENTION_CTRL, RETENTION_WAIT, 27, 5) + FIELD(RTC_CNTL_RTC_CNTL_RETENTION_CTRL, RETENTION_EN, 26, 1) + FIELD(RTC_CNTL_RTC_CNTL_RETENTION_CTRL, RETENTION_CLKOFF_WAIT, 22, 4) + FIELD(RTC_CNTL_RTC_CNTL_RETENTION_CTRL, RETENTION_DONE_WAIT, 19, 3) + FIELD(RTC_CNTL_RTC_CNTL_RETENTION_CTRL, RETENTION_CLK_SEL, 18, 1) + +REG32(RTC_CNTL_RTC_FIB_SEL, 0x010C) + FIELD(RTC_CNTL_RTC_FIB_SEL, RTC_FIB_SEL, 0, 3) + +REG32(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, 0x0110) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_PIN0_WAKEUP_ENABLE, 31, 1) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_PIN1_WAKEUP_ENABLE, 30, 1) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_PIN2_WAKEUP_ENABLE, 29, 1) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_PIN3_WAKEUP_ENABLE, 28, 1) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_PIN4_WAKEUP_ENABLE, 27, 1) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_PIN5_WAKEUP_ENABLE, 26, 1) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_PIN0_INT_TYPE, 23, 3) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_PIN1_INT_TYPE, 20, 3) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_PIN2_INT_TYPE, 17, 3) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_PIN3_INT_TYPE, 14, 3) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_PIN4_INT_TYPE, 11, 3) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_PIN5_INT_TYPE, 8, 3) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_PIN_CLK_GATE, 7, 1) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_WAKEUP_STATUS_CLR, 6, 1) + FIELD(RTC_CNTL_RTC_CNTL_GPIO_WAKEUP, RTC_GPIO_WAKEUP_STATUS, 0, 6) + +REG32(RTC_CNTL_RTC_CNTL_DBG_SEL, 0x0114) + +REG32(RTC_CNTL_RTC_CNTL_DBG_MAP, 0x0118) + +REG32(RTC_CNTL_RTC_CNTL_SENSOR_CTRL, 0x011C) + FIELD(RTC_CNTL_RTC_CNTL_SENSOR_CTRL, FORCE_XPD_SAR, 30, 2) + FIELD(RTC_CNTL_RTC_CNTL_SENSOR_CTRL, SAR2_PWDET_CCT, 27, 3) + +REG32(RTC_CNTL_RTC_CNTL_DBG_SAR_SEL, 0x0120) + FIELD(RTC_CNTL_RTC_CNTL_DBG_SAR_SEL, SAR_DEBUG_SEL, 27, 5) + +REG32(RTC_CNTL_RTC_CNTL_PG_CTRL, 0x0124) + FIELD(RTC_CNTL_RTC_CNTL_PG_CTRL, POWER_GLITCH_EN, 31, 1) + FIELD(RTC_CNTL_RTC_CNTL_PG_CTRL, POWER_GLITCH_EFUSE_SEL, 30, 1) + FIELD(RTC_CNTL_RTC_CNTL_PG_CTRL, POWER_GLITCH_FORCE_PU, 29, 1) + FIELD(RTC_CNTL_RTC_CNTL_PG_CTRL, POWER_GLITCH_FORCE_PD, 28, 1) + FIELD(RTC_CNTL_RTC_CNTL_PG_CTRL, POWER_GLITCH_DSENSE, 26, 2) + +REG32(RTC_CNTL_DATE, 0x01fc) diff --git a/include/hw/misc/esp32c3_sha.h b/include/hw/misc/esp32c3_sha.h new file mode 100644 index 000000000000..598dae2b826d --- /dev/null +++ b/include/hw/misc/esp32c3_sha.h @@ -0,0 +1,114 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/esp32c3_reg.h" +#include "crypto/sha256_i.h" +#include "crypto/sha224_i.h" +#include "crypto/sha1_i.h" +#include "hw/dma/esp32c3_gdma.h" + +#define TYPE_ESP32C3_SHA "misc.esp32c3.sha" +#define ESP32C3_SHA(obj) OBJECT_CHECK(ESP32C3ShaState, (obj), TYPE_ESP32C3_SHA) + +#define ESP32C3_SHA_REGS_SIZE (0xC0) + + +/** + * @brief Size of the message array, in bytes + */ +#define ESP32C3_MESSAGE_SIZE 64 +#define ESP32C3_MESSAGE_WORDS (ESP32C3_MESSAGE_SIZE / sizeof(uint32_t)) + + +/** + * @brief Mode configuration for the SHA_MODE register. + */ +typedef enum { + ESP32C3_SHA_1_MODE = 0, + ESP32C3_SHA_224_MODE = 1, + ESP32C3_SHA_256_MODE = 2, +} ESP32C3ShaMode; + + +typedef union { + struct sha256_state sha256; + struct sha1_state sha1; +} ESP32C3HashContext; + + +typedef void (*hash_init)(void *); +typedef void (*hash_compress)(void *, const uint8_t*); + +typedef struct { + hash_init init; + /* For all types of hash, the message to "compress" must be 64-byte long (16 words of 32 bits) */ + hash_compress compress; + /* Length of the context in bytes */ + size_t len; +} ESP32C3HashAlg; + + +typedef struct ESP32C3ShaState { + SysBusDevice parent_obj; + MemoryRegion iomem; + + /* SHA mode selected by the application */ + ESP32C3ShaMode mode; + /* Context for the hash calculation */ + ESP32C3HashContext context; + + /* Resulted hash value */ + uint32_t hash[8]; + /* User data value */ + uint32_t message[ESP32C3_MESSAGE_WORDS]; + + /* DMA related */ + /* Number of block to process in DMA mode */ + uint32_t block; + bool int_ena; + qemu_irq irq; + + /* Public: must be set before realizing instance*/ + ESP32C3GdmaState *gdma; +} ESP32C3ShaState; + + +REG32(SHA_MODE, 0x000) + FIELD(SHA_MODE, MODE, 0, 3) + +REG32(SHA_T_STRING, 0x004) + +REG32(SHA_T_LENGTH, 0x008) + +REG32(SHA_DMA_BLOCK_NUM, 0x00C) + FIELD(SHA_DMA_BLOCK_NUM, DMA_BLOCK_NUM, 0, 6) + +REG32(SHA_START, 0x010) + FIELD(SHA_START, START, 0, 1) + +REG32(SHA_CONTINUE, 0x014) + FIELD(SHA_CONTINUE, CONTINUE, 0, 1) + +REG32(SHA_BUSY, 0x018) + FIELD(SHA_BUSY, BUSY_STATE, 0, 1) + +REG32(SHA_DMA_START, 0x01C) + FIELD(SHA_DMA_START, DMA_START, 0, 1) + +REG32(SHA_DMA_CONTINUE, 0x020) + FIELD(SHA_DMA_CONTINUE, DMA_CONTINUE, 0, 1) + +REG32(SHA_CLEAR_IRQ, 0x024) + FIELD(SHA_CLEAR_IRQ, CLEAR_INTERRUPT, 0, 1) + +REG32(SHA_IRQ_ENA, 0x028) + FIELD(SHA_IRQ_ENA, INTERRUPT_ENA, 0, 1) + +REG32(SHA_DATE, 0x02C) + FIELD(SHA_DATE, DATE, 0, 30) + +REG32(SHA_H_MEM, 0x040) + +REG32(SHA_M_MEM, 0x080) diff --git a/include/hw/misc/ssi_psram.h b/include/hw/misc/ssi_psram.h new file mode 100644 index 000000000000..5585bd2b6a91 --- /dev/null +++ b/include/hw/misc/ssi_psram.h @@ -0,0 +1,18 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/ssi/ssi.h" +#include "qom/object.h" + +typedef struct SsiPsramState { + SSIPeripheral parent_obj; + uint32_t size_mbytes; + int dummy; + int command; + int byte_count; +} SsiPsramState; + +#define TYPE_SSI_PSRAM "ssi_psram" +OBJECT_DECLARE_SIMPLE_TYPE(SsiPsramState, SSI_PSRAM) + diff --git a/include/hw/misc/unimp-default.h b/include/hw/misc/unimp-default.h new file mode 100644 index 000000000000..2ee8c5ad6a8e --- /dev/null +++ b/include/hw/misc/unimp-default.h @@ -0,0 +1,58 @@ +/* + * "Unimplemented" device with default value + * + * Copyright Linaro Limited, 2017 + * Written by Peter Maydell + * Modified by redfast00 2023 + */ + +#ifndef HW_MISC_UNIMP_DEFAULT_H +#define HW_MISC_UNIMP_DEFAULT_H + +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "qapi/error.h" +#include "qom/object.h" + +#define TYPE_UNIMPLEMENTED_DEFAULT_DEVICE "unimplemented-default-device" + +OBJECT_DECLARE_SIMPLE_TYPE(UnimplementedDefaultDeviceState, UNIMPLEMENTED_DEFAULT_DEVICE) + +struct UnimplementedDefaultDeviceState { + SysBusDevice parent_obj; + MemoryRegion iomem; + unsigned offset_fmt_width; + char *name; + uint64_t size; + uint64_t default_value; +}; + +/** + * create_unimplemented_default_device: create and map a dummy device with default value + * @name: name of the device for debug logging + * @base: base address of the device's MMIO region + * @size: size of the device's MMIO region + * @default_value: value returned for read operations + * + * This utility function creates and maps an instance of unimplemented-device, + * which is a dummy device which simply logs all guest accesses to + * it via the qemu_log LOG_UNIMP debug log. + * The device is mapped at priority -1000, which means that you can + * use it to cover a large region and then map other devices on top of it + * if necessary. + */ +static inline void create_unimplemented_default_device(const char *name, + hwaddr base, + hwaddr size, uint64_t default_value) +{ + DeviceState *dev = qdev_new(TYPE_UNIMPLEMENTED_DEFAULT_DEVICE); + + qdev_prop_set_string(dev, "name", name); + qdev_prop_set_uint64(dev, "size", size); + qdev_prop_set_uint64(dev, "default_value", default_value); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + sysbus_mmio_map_overlap(SYS_BUS_DEVICE(dev), 0, base, -1000); +} + +#endif diff --git a/include/hw/nvram/esp32_efuse.h b/include/hw/nvram/esp32_efuse.h new file mode 100644 index 000000000000..29bb99c01fcf --- /dev/null +++ b/include/hw/nvram/esp32_efuse.h @@ -0,0 +1,131 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32_reg.h" +#include "sysemu/block-backend.h" + +#define TYPE_ESP32_EFUSE "nvram.esp32.efuse" +#define ESP32_EFUSE(obj) OBJECT_CHECK(Esp32EfuseState, (obj), TYPE_ESP32_EFUSE) + +REG32(EFUSE_BLK0_RDATA0, 0x00) +REG32(EFUSE_BLK0_WDATA0, 0x1c) +REG32(EFUSE_BLK1_RDATA0, 0x38) +REG32(EFUSE_BLK2_RDATA0, 0x58) +REG32(EFUSE_BLK3_RDATA0, 0x78) +REG32(EFUSE_BLK1_WDATA0, 0x98) +REG32(EFUSE_BLK2_WDATA0, 0xb8) +REG32(EFUSE_BLK3_WDATA0, 0xd8) +REG32(EFUSE_CLK, 0xf8) +REG32(EFUSE_CONF, 0xfc) + FIELD(EFUSE_CONF, OP_CODE, 0, 16) +REG32(EFUSE_STATUS, 0x100) +REG32(EFUSE_CMD, 0x104) +REG32(EFUSE_INT_RAW, 0x108) +REG32(EFUSE_INT_ST, 0x10c) +REG32(EFUSE_INT_ENA, 0x110) +REG32(EFUSE_INT_CLR, 0x114) +REG32(EFUSE_DAC_CONF, 0x118) +REG32(EFUSE_DEC_STATUS, 0x11c) +REG32(EFUSE_DATE, 0x1fc) + +/* the following bit masks apply to CMD, INT_RAW, INT_ST, INT_ENA, INT_CLR */ +#define EFUSE_READ 0x01 +#define EFUSE_PGM 0x02 + +/* expected values of EFUSE_CONF OP_CODE field */ +#define EFUSE_READ_OP_CODE 0x5AA5 +#define EFUSE_PGM_OP_CODE 0x5A5A + +#define ESP32_EFUSE_UPDATE_GPIO "efuse-update" + + +typedef struct Esp32EfuseRegs { + union { + struct { + struct { + uint32_t wr_dis_rd_dis : 1; + uint32_t wr_dis_wr_dis : 1; + uint32_t wr_dis_flash_crypt_cnt : 1; + uint32_t wr_dis_mac_spi_config : 1; + uint32_t wr_dis_unused1 : 1; + uint32_t wr_dis_xpd_sdio : 1; + uint32_t wr_dis_spi_pad_config : 1; + uint32_t wr_dis_blk1 : 1; + uint32_t wr_dis_blk2 : 1; + uint32_t wr_dis_blk3 : 1; + uint32_t wr_dis_flash_crypt_coding_scheme : 1; + uint32_t wr_dis_unused2 : 1; + uint32_t wr_dis_abs_done_0 : 1; + uint32_t wr_dis_abs_done_1 : 1; + uint32_t wr_dis_jtag_disable : 1; + uint32_t wr_dis_console_dl_disable : 1; + + uint32_t rd_dis_blk1 : 1; + uint32_t rd_dis_blk2 : 1; + uint32_t rd_dis_blk3 : 1; + uint32_t rd_dis_blk0_partial : 1; + + uint32_t flash_crypt_cnt : 7; + } blk0_d0; + uint32_t blk0_d1; + uint32_t blk0_d2; + uint32_t blk0_d3; + uint32_t blk0_d4; + struct { + uint32_t blk0_d5_misc : 28; + uint32_t flash_crypt_config : 4; + } blk0_d5; + struct { + uint32_t coding_scheme : 2; + uint32_t console_debug_dis : 1; + uint32_t dis_sdio_host : 1; + uint32_t abs_done_0 : 1; + uint32_t abs_done_1 : 1; + uint32_t dis_jtag : 1; + uint32_t dis_dl_encrypt : 1; + uint32_t dis_dl_decrypt : 1; + uint32_t dis_dl_cache : 1; + uint32_t key_status : 1; + } blk0_d6; + }; + uint32_t blk0[7]; + }; + uint32_t blk1[8]; + uint32_t blk2[8]; + uint32_t blk3[8]; +} Esp32EfuseRegs; + + +typedef struct Esp32EfuseState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + qemu_irq irq; + BlockBackend *blk; + QEMUTimer op_timer; + qemu_irq efuse_update_gpio; + + Esp32EfuseRegs efuse_wr; + Esp32EfuseRegs efuse_wr_dis; + Esp32EfuseRegs efuse_rd; + Esp32EfuseRegs efuse_rd_dis; + + uint32_t clk_reg; + uint32_t conf_reg; + uint32_t status_reg; + uint32_t cmd_reg; + uint32_t int_raw_reg; + uint32_t int_st_reg; + uint32_t int_ena_reg; + uint32_t dac_conf_reg; +} Esp32EfuseState; + +/* returns NULL unless there is exactly one device */ +static inline Esp32EfuseState *esp32_efuse_find(void) +{ + Object *o = object_resolve_path_type("", TYPE_ESP32_EFUSE, NULL); + + return o ? ESP32_EFUSE(o) : NULL; +} diff --git a/include/hw/nvram/esp32c3_efuse.h b/include/hw/nvram/esp32c3_efuse.h new file mode 100644 index 000000000000..9df827c96ba3 --- /dev/null +++ b/include/hw/nvram/esp32c3_efuse.h @@ -0,0 +1,552 @@ +/* + * ESP32-C3 eFuse emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#pragma once + +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32c3_reg.h" +#include "sysemu/block-backend.h" + +#define TYPE_ESP32C3_EFUSE "nvram.esp32c3.efuse" +#define ESP32C3_EFUSE(obj) OBJECT_CHECK(ESP32C3EfuseState, (obj), TYPE_ESP32C3_EFUSE) + +#define ESP32C3_EFUSE_IO_RANGE_SIZE (sizeof(ESP32C3EfuseRegs)) + +/** + * Size of the efuses in bytes on the ESP32C3 + */ +#define ESP32C3_EFUSE_BYTE_COUNT (4096/4) + +/** + * Number of data registers used when programming efuses + */ +#define ESP32C3_EFUSE_PGM_DATA_COUNT 8 + +/** + * Number of check registers used when programming efuses + */ +#define ESP32C3_EFUSE_PGM_CHECK_COUNT 3 + +/** + * Start address of the different BLOCKs in the ESP32C3EfuseRegs structure + */ +#define ESP32C3_EFUSE_BLOCK0_ADDR 0x002c +#define ESP32C3_EFUSE_BLOCK1_ADDR 0x0044 +#define ESP32C3_EFUSE_BLOCK2_ADDR 0x005c +#define ESP32C3_EFUSE_BLOCK3_ADDR 0x007c +#define ESP32C3_EFUSE_BLOCK4_ADDR 0x009c +#define ESP32C3_EFUSE_BLOCK5_ADDR 0x00bc +#define ESP32C3_EFUSE_BLOCK6_ADDR 0x00dc +#define ESP32C3_EFUSE_BLOCK7_ADDR 0x00fc +#define ESP32C3_EFUSE_BLOCK8_ADDR 0x011c +#define ESP32C3_EFUSE_BLOCK9_ADDR 0x013c +#define ESP32C3_EFUSE_BLOCK10_ADDR 0x015c + + +/** + * Size of BLOCK0 in 32-bit word unit + */ +#define ESP32C3_EFUSE_BLOCK0_WORDS 6 + +/** + * Magic values for write and read operations + */ +#define EFUSE_WRITE_OPCODE 0x5A5A +#define EFUSE_READ_OPCODE 0x5AA5 + + +/* Structure definition taken from `esp32c3/soc/efuse_struct.h` and re-adapted with few arrays */ +struct ESP32C3EfuseRegs { + uint32_t pgm_data[ESP32C3_EFUSE_PGM_DATA_COUNT]; /*Registers that stores data to be programmed.*/ + uint32_t pgm_check[ESP32C3_EFUSE_PGM_CHECK_COUNT]; /*Registers that stores the RS code to be programmed.*/ + uint32_t rd_wr_dis; /*BLOCK0 data register $n.*/ + union { + struct { + uint32_t rd_dis: 7; /*The value of RD_DIS.*/ + uint32_t rpt4_reserved5: 1; /*Reserved*/ + uint32_t dis_icache: 1; /*The value of DIS_ICACHE.*/ + uint32_t dis_usb_jtag: 1; /*The value of DIS_USB_JTAG.*/ + uint32_t dis_download_icache: 1; /*The value of DIS_DOWNLOAD_ICACHE.*/ + uint32_t dis_usb_device: 1; /*The value of DIS_USB_DEVICE.*/ + uint32_t dis_force_download: 1; /*The value of DIS_FORCE_DOWNLOAD.*/ + uint32_t dis_usb: 1; /*The value of DIS_USB.*/ + uint32_t dis_can: 1; /*The value of DIS_CAN.*/ + uint32_t jtag_sel_enable: 1; /*The value of JTAG_SEL_ENABLE.*/ + uint32_t soft_dis_jtag: 3; /*The value of SOFT_DIS_JTAG.*/ + uint32_t dis_pad_jtag: 1; /*The value of DIS_PAD_JTAG.*/ + uint32_t dis_download_manual_encrypt: 1; /*The value of DIS_DOWNLOAD_MANUAL_ENCRYPT.*/ + uint32_t usb_drefh: 2; /*The value of USB_DREFH.*/ + uint32_t usb_drefl: 2; /*The value of USB_DREFL.*/ + uint32_t usb_exchg_pins: 1; /*The value of USB_EXCHG_PINS.*/ + uint32_t vdd_spi_as_gpio: 1; /*The value of VDD_SPI_AS_GPIO.*/ + uint32_t btlc_gpio_enable: 2; /*The value of BTLC_GPIO_ENABLE.*/ + uint32_t powerglitch_en: 1; /*The value of POWERGLITCH_EN.*/ + uint32_t power_glitch_dsense: 2; /*The value of POWER_GLITCH_DSENSE.*/ + }; + uint32_t val; + } rd_repeat_data0; + union { + struct { + uint32_t rpt4_reserved2: 16; /*Reserved.*/ + uint32_t wdt_delay_sel: 2; /*The value of WDT_DELAY_SEL.*/ + uint32_t spi_boot_crypt_cnt: 3; /*The value of SPI_BOOT_CRYPT_CNT.*/ + uint32_t secure_boot_key_revoke0: 1; /*The value of SECURE_BOOT_KEY_REVOKE0.*/ + uint32_t secure_boot_key_revoke1: 1; /*The value of SECURE_BOOT_KEY_REVOKE1.*/ + uint32_t secure_boot_key_revoke2: 1; /*The value of SECURE_BOOT_KEY_REVOKE2.*/ + uint32_t key_purpose_0: 4; /*The value of KEY_PURPOSE_0.*/ + uint32_t key_purpose_1: 4; /*The value of KEY_PURPOSE_1.*/ + }; + uint32_t val; + } rd_repeat_data1; + union { + struct { + uint32_t key_purpose_2: 4; /*The value of KEY_PURPOSE_2.*/ + uint32_t key_purpose_3: 4; /*The value of KEY_PURPOSE_3.*/ + uint32_t key_purpose_4: 4; /*The value of KEY_PURPOSE_4.*/ + uint32_t key_purpose_5: 4; /*The value of KEY_PURPOSE_5.*/ + uint32_t rpt4_reserved3: 4; /*Reserved.*/ + uint32_t secure_boot_en: 1; /*The value of SECURE_BOOT_EN.*/ + uint32_t secure_boot_aggressive_revoke: 1; /*The value of SECURE_BOOT_AGGRESSIVE_REVOKE.*/ + uint32_t rpt4_reserved0: 6; /*Reserved.*/ + uint32_t flash_tpuw: 4; /*The value of FLASH_TPUW.*/ + }; + uint32_t val; + } rd_repeat_data2; + union { + struct { + uint32_t dis_download_mode: 1; /*The value of DIS_DOWNLOAD_MODE.*/ + uint32_t dis_direct_boot: 1; /*The value of DIS_DIRECT_BOOT.*/ + uint32_t dis_usb_serial_jtag_rom_print:1; /*The value of DIS_USB_SERIAL_JTAG_ROM_PRINT.*/ + uint32_t rpt4_reserved8: 1; /*Reserved.*/ + uint32_t dis_usb_serial_jtag_download_mode: 1; /*The value of dis_usb_serial_jtag_download_mode.*/ + uint32_t enable_security_download: 1; /*The value of ENABLE_SECURITY_DOWNLOAD.*/ + uint32_t uart_print_control: 2; /*The value of UART_PRINT_CONTROL.*/ + uint32_t rpt4_reserved7: 5; /*Reserved.*/ + uint32_t force_send_resume: 1; /*The value of FORCE_SEND_RESUME.*/ + uint32_t secure_version: 16; /*The value of SECURE_VERSION.*/ + uint32_t rpt4_reserved1: 1; /*Reserved.*/ + uint32_t err_rst_enable: 1; /*Use BLOCK0 to check error record registers, 0 - without check.*/ + }; + uint32_t val; + } rd_repeat_data3; + union { + struct { + uint32_t disable_wafer_version_major: 1; + uint32_t disable_blk_version_major: 1; + uint32_t rpt4_reserved4:22; /*Reserved.*/ + uint32_t reserved24: 8; /*Reserved.*/ + }; + uint32_t val; + } rd_repeat_data4; + uint32_t rd_mac_spi_sys_0; /*BLOCK1 data register $n.*/ + union { + struct { + uint32_t mac_1: 16; /*Stores the high 16 bits of MAC address.*/ + uint32_t spi_pad_conf_0:16; /*Stores the zeroth part of SPI_PAD_CONF.*/ + }; + uint32_t val; + } rd_mac_spi_sys_1; + uint32_t rd_mac_spi_sys_2; /*BLOCK1 data register $n.*/ + union { + struct { + uint32_t spi_pad_conf_2: 18; /*Stores the second part of SPI_PAD_CONF.*/ + uint32_t wafer_version_minor_low: 3; + uint32_t pkg_version: 3; + uint32_t blk_version_minor:3; + uint32_t sys_data_part0_0: 5; + }; + uint32_t val; + } rd_mac_spi_sys_3; + union { + struct { + uint32_t reserved1: 7; + uint32_t k_rtc_ldo: 7; + uint32_t k_dig_ldo: 7; + uint32_t v_rtc_dbias20: 8; + uint32_t v_dig_dbias20_low: 3; + }; + uint32_t val; + } rd_mac_spi_sys_4; /*BLOCK1 data register $n.*/ + union { + struct { + uint32_t v_dig_dbias20_hi: 5; + uint32_t dig_dbias_hvt: 5; + uint32_t reserved1: 13; + uint32_t wafer_version_minor_high: 1; + uint32_t wafer_version_major: 2; + uint32_t reserved2: 6; + }; + uint32_t val; + } rd_mac_spi_sys_5; /*BLOCK1 data register $n.*/ + uint32_t rd_sys_part1_data0; /*Register $n of BLOCK2 (system).*/ + uint32_t rd_sys_part1_data1; /*Register $n of BLOCK2 (system).*/ + uint32_t rd_sys_part1_data2; /*Register $n of BLOCK2 (system).*/ + uint32_t rd_sys_part1_data3; /*Register $n of BLOCK2 (system).*/ + union { + struct { + uint32_t blk_version_major: 2; + uint32_t reserved1: 10; + uint32_t ocode: 8; + uint32_t reserved2: 12; + }; + uint32_t val; + } rd_sys_part1_data4; /*Register $n of BLOCK2 (system).*/ + uint32_t rd_sys_part1_data5; /*Register $n of BLOCK2 (system).*/ + uint32_t rd_sys_part1_data6; /*Register $n of BLOCK2 (system).*/ + uint32_t rd_sys_part1_data7; /*Register $n of BLOCK2 (system).*/ + uint32_t rd_usr_data0; /*Register $n of BLOCK3 (user).*/ + uint32_t rd_usr_data1; /*Register $n of BLOCK3 (user).*/ + uint32_t rd_usr_data2; /*Register $n of BLOCK3 (user).*/ + uint32_t rd_usr_data3; /*Register $n of BLOCK3 (user).*/ + uint32_t rd_usr_data4; /*Register $n of BLOCK3 (user).*/ + uint32_t rd_usr_data5; /*Register $n of BLOCK3 (user).*/ + uint32_t rd_usr_data6; /*Register $n of BLOCK3 (user).*/ + uint32_t rd_usr_data7; /*Register $n of BLOCK3 (user).*/ + uint32_t rd_key0_data0; /*Register $n of BLOCK4 (KEY0).*/ + uint32_t rd_key0_data1; /*Register $n of BLOCK4 (KEY0).*/ + uint32_t rd_key0_data2; /*Register $n of BLOCK4 (KEY0).*/ + uint32_t rd_key0_data3; /*Register $n of BLOCK4 (KEY0).*/ + uint32_t rd_key0_data4; /*Register $n of BLOCK4 (KEY0).*/ + uint32_t rd_key0_data5; /*Register $n of BLOCK4 (KEY0).*/ + uint32_t rd_key0_data6; /*Register $n of BLOCK4 (KEY0).*/ + uint32_t rd_key0_data7; /*Register $n of BLOCK4 (KEY0).*/ + uint32_t rd_key1_data0; /*Register $n of BLOCK5 (KEY1).*/ + uint32_t rd_key1_data1; /*Register $n of BLOCK5 (KEY1).*/ + uint32_t rd_key1_data2; /*Register $n of BLOCK5 (KEY1).*/ + uint32_t rd_key1_data3; /*Register $n of BLOCK5 (KEY1).*/ + uint32_t rd_key1_data4; /*Register $n of BLOCK5 (KEY1).*/ + uint32_t rd_key1_data5; /*Register $n of BLOCK5 (KEY1).*/ + uint32_t rd_key1_data6; /*Register $n of BLOCK5 (KEY1).*/ + uint32_t rd_key1_data7; /*Register $n of BLOCK5 (KEY1).*/ + uint32_t rd_key2_data0; /*Register $n of BLOCK6 (KEY2).*/ + uint32_t rd_key2_data1; /*Register $n of BLOCK6 (KEY2).*/ + uint32_t rd_key2_data2; /*Register $n of BLOCK6 (KEY2).*/ + uint32_t rd_key2_data3; /*Register $n of BLOCK6 (KEY2).*/ + uint32_t rd_key2_data4; /*Register $n of BLOCK6 (KEY2).*/ + uint32_t rd_key2_data5; /*Register $n of BLOCK6 (KEY2).*/ + uint32_t rd_key2_data6; /*Register $n of BLOCK6 (KEY2).*/ + uint32_t rd_key2_data7; /*Register $n of BLOCK6 (KEY2).*/ + uint32_t rd_key3_data0; /*Register $n of BLOCK7 (KEY3).*/ + uint32_t rd_key3_data1; /*Register $n of BLOCK7 (KEY3).*/ + uint32_t rd_key3_data2; /*Register $n of BLOCK7 (KEY3).*/ + uint32_t rd_key3_data3; /*Register $n of BLOCK7 (KEY3).*/ + uint32_t rd_key3_data4; /*Register $n of BLOCK7 (KEY3).*/ + uint32_t rd_key3_data5; /*Register $n of BLOCK7 (KEY3).*/ + uint32_t rd_key3_data6; /*Register $n of BLOCK7 (KEY3).*/ + uint32_t rd_key3_data7; /*Register $n of BLOCK7 (KEY3).*/ + uint32_t rd_key4_data0; /*Register $n of BLOCK8 (KEY4).*/ + uint32_t rd_key4_data1; /*Register $n of BLOCK8 (KEY4).*/ + uint32_t rd_key4_data2; /*Register $n of BLOCK8 (KEY4).*/ + uint32_t rd_key4_data3; /*Register $n of BLOCK8 (KEY4).*/ + uint32_t rd_key4_data4; /*Register $n of BLOCK8 (KEY4).*/ + uint32_t rd_key4_data5; /*Register $n of BLOCK8 (KEY4).*/ + uint32_t rd_key4_data6; /*Register $n of BLOCK8 (KEY4).*/ + uint32_t rd_key4_data7; /*Register $n of BLOCK8 (KEY4).*/ + uint32_t rd_key5_data0; /*Register $n of BLOCK9 (KEY5).*/ + uint32_t rd_key5_data1; /*Register $n of BLOCK9 (KEY5).*/ + uint32_t rd_key5_data2; /*Register $n of BLOCK9 (KEY5).*/ + uint32_t rd_key5_data3; /*Register $n of BLOCK9 (KEY5).*/ + uint32_t rd_key5_data4; /*Register $n of BLOCK9 (KEY5).*/ + uint32_t rd_key5_data5; /*Register $n of BLOCK9 (KEY5).*/ + uint32_t rd_key5_data6; /*Register $n of BLOCK9 (KEY5).*/ + uint32_t rd_key5_data7; /*Register $n of BLOCK9 (KEY5).*/ + uint32_t rd_sys_part2_data0; /*Register $n of BLOCK10 (system).*/ + uint32_t rd_sys_part2_data1; /*Register $n of BLOCK10 (system).*/ + uint32_t rd_sys_part2_data2; /*Register $n of BLOCK10 (system).*/ + uint32_t rd_sys_part2_data3; /*Register $n of BLOCK10 (system).*/ + uint32_t rd_sys_part2_data4; /*Register $n of BLOCK10 (system).*/ + uint32_t rd_sys_part2_data5; /*Register $n of BLOCK10 (system).*/ + uint32_t rd_sys_part2_data6; /*Register $n of BLOCK10 (system).*/ + uint32_t rd_sys_part2_data7; /*Register $n of BLOCK10 (system).*/ + union { + struct { + uint32_t rd_dis_err: 7; /*If any bit in RD_DIS is 1 then it indicates a programming error.*/ + uint32_t rpt4_reserved5_err: 1; /*Reserved.*/ + uint32_t dis_icache_err: 1; /*If DIS_ICACHE is 1 then it indicates a programming error.*/ + uint32_t dis_usb_jtag_err: 1; /*If DIS_USB_JTAG is 1 then it indicates a programming error.*/ + uint32_t dis_download_icache: 1; /*If DIS_DOWNLOAD_ICACHE is 1 then it indicates a programming error.*/ + uint32_t dis_usb_device_err: 1; /*If DIS_USB_DEVICE is 1 then it indicates a programming error.*/ + uint32_t dis_force_download_err: 1; /*If DIS_FORCE_DOWNLOAD is 1 then it indicates a programming error.*/ + uint32_t dis_usb_err: 1; /*If DIS_USB is 1 then it indicates a programming error.*/ + uint32_t dis_can_err: 1; /*If DIS_CAN is 1 then it indicates a programming error.*/ + uint32_t jtag_sel_enable_err: 1; /*If JTAG_SEL_ENABLE is 1 then it indicates a programming error.*/ + uint32_t soft_dis_jtag_err: 3; /*If SOFT_DIS_JTAG is 1 then it indicates a programming error.*/ + uint32_t dis_pad_jtag_err: 1; /*If DIS_PAD_JTAG is 1 then it indicates a programming error.*/ + uint32_t dis_download_manual_encrypt_err: 1; /*If DIS_DOWNLOAD_MANUAL_ENCRYPT is 1 then it indicates a programming error.*/ + uint32_t usb_drefh_err: 2; /*If any bit in USB_DREFH is 1 then it indicates a programming error.*/ + uint32_t usb_drefl_err: 2; /*If any bit in USB_DREFL is 1 then it indicates a programming error.*/ + uint32_t usb_exchg_pins_err: 1; /*If USB_EXCHG_PINS is 1 then it indicates a programming error.*/ + uint32_t vdd_spi_as_gpio_err: 1; /*If VDD_SPI_AS_GPIO is 1 then it indicates a programming error.*/ + uint32_t btlc_gpio_enable_err: 2; /*If any bit in BTLC_GPIO_ENABLE is 1 then it indicates a programming error.*/ + uint32_t powerglitch_en_err: 1; /*If POWERGLITCH_EN is 1 then it indicates a programming error.*/ + uint32_t power_glitch_dsense_err: 2; /*If any bit in POWER_GLITCH_DSENSE is 1 then it indicates a programming error.*/ + }; + uint32_t val; + } rd_repeat_err0; + union { + struct { + uint32_t rpt4_reserved2_err: 16; /*Reserved.*/ + uint32_t wdt_delay_sel_err: 2; /*If any bit in WDT_DELAY_SEL is 1 then it indicates a programming error.*/ + uint32_t spi_boot_crypt_cnt_err: 3; /*If any bit in SPI_BOOT_CRYPT_CNT is 1 then it indicates a programming error.*/ + uint32_t secure_boot_key_revoke0_err: 1; /*If SECURE_BOOT_KEY_REVOKE0 is 1 then it indicates a programming error.*/ + uint32_t secure_boot_key_revoke1_err: 1; /*If SECURE_BOOT_KEY_REVOKE1 is 1 then it indicates a programming error.*/ + uint32_t secure_boot_key_revoke2_err: 1; /*If SECURE_BOOT_KEY_REVOKE2 is 1 then it indicates a programming error.*/ + uint32_t key_purpose_0_err: 4; /*If any bit in KEY_PURPOSE_0 is 1 then it indicates a programming error.*/ + uint32_t key_purpose_1_err: 4; /*If any bit in KEY_PURPOSE_1 is 1 then it indicates a programming error.*/ + }; + uint32_t val; + } rd_repeat_err1; + union { + struct { + uint32_t key_purpose_2_err: 4; /*If any bit in KEY_PURPOSE_2 is 1 then it indicates a programming error.*/ + uint32_t key_purpose_3_err: 4; /*If any bit in KEY_PURPOSE_3 is 1 then it indicates a programming error.*/ + uint32_t key_purpose_4_err: 4; /*If any bit in KEY_PURPOSE_4 is 1 then it indicates a programming error.*/ + uint32_t key_purpose_5_err: 4; /*If any bit in KEY_PURPOSE_5 is 1 then it indicates a programming error.*/ + uint32_t rpt4_reserved3_err: 4; /*Reserved.*/ + uint32_t secure_boot_en_err: 1; /*If SECURE_BOOT_EN is 1 then it indicates a programming error.*/ + uint32_t secure_boot_aggressive_revoke_err: 1; /*If SECURE_BOOT_AGGRESSIVE_REVOKE is 1 then it indicates a programming error.*/ + uint32_t rpt4_reserved0_err: 6; /*Reserved.*/ + uint32_t flash_tpuw_err: 4; /*If any bit in FLASH_TPUM is 1 then it indicates a programming error.*/ + }; + uint32_t val; + } rd_repeat_err2; + union { + struct { + uint32_t dis_download_mode_err: 1; /*If the value is not zero then it indicates a programming error on DIS_DOWNLOAD_MODE.*/ + uint32_t dis_direct_boot_err: 1; /*If the value is not zero then it indicates a programming error on DIS_DIRECT_BOOT.*/ + uint32_t dis_usb_serial_jtag_rom_print_err:1; /*If the value is not zero then it indicates a programming error on DIS_USB_SERIAL_JTAG_ROM_PRINT.*/ + uint32_t rpt4_reserved8_err: 1; /*Reserved.*/ + uint32_t dis_usb_serial_jtag_download_mode_err: 1; /*If the value is not zero then it indicates a programming error on DIS_USB_SERIAL_JTAG_DOWNLOAD_MODE.*/ + uint32_t enable_security_download_err: 1; /*If the value is not zero then it indicates a programming error on ENABLE_SECURITY_DOWNLOAD.*/ + uint32_t uart_print_control_err: 2; /*If the value is not zero then it indicates a programming error on UART_PRINT_CONTROL.*/ + uint32_t rpt4_reserved7_err: 5; /*Reserved*/ + uint32_t force_send_resume_err: 1; /*If the value is not zero then it indicates a programming error on FORCE_SEND_RESUME.*/ + uint32_t secure_version_err: 16; /*If the value is not zero then it indicates a programming error on SECURE_VERSION.*/ + uint32_t rpt4_reserved1_err: 1; /*Reserved.*/ + uint32_t err_rst_enable_err: 1; /*Use BLOCK0 to check error record registers, 0 - without check.*/ + }; + uint32_t val; + } rd_repeat_err3; + union { + struct { + uint32_t rpt4_reserved4_err:24; /*Reserved.*/ + uint32_t reserved24: 8; /*Reserved.*/ + }; + uint32_t val; + } rd_repeat_err4; + uint32_t reserved_190; + uint32_t reserved_194; + uint32_t reserved_198; + uint32_t reserved_19c; + uint32_t reserved_1a0; + uint32_t reserved_1a4; + uint32_t reserved_1a8; + uint32_t reserved_1ac; + uint32_t reserved_1b0; + uint32_t reserved_1b4; + uint32_t reserved_1b8; + uint32_t reserved_1bc; + union { + struct { + uint32_t mac_spi_8m_err_num: 3; /*The value of this signal means the number of error bytes.*/ + uint32_t reserved3: 1; /*Reserved.*/ + uint32_t sys_part1_num: 3; /*The value of this signal means the number of error bytes.*/ + uint32_t mac_spi_8m_fail: 1; /*0: Means no failure and that the data of MAC_SPI_8M is reliable 1: Means that programming MAC_SPI_8M failed and the number of error bytes is over 6.*/ + uint32_t usr_data_err_num: 3; /*The value of this signal means the number of error bytes.*/ + uint32_t sys_part1_fail: 1; /*0: Means no failure and that the data of system part1 is reliable 1: Means that programming the data of system part1 failed and the number of error bytes is over 6.*/ + uint32_t key0_err_num: 3; /*The value of this signal means the number of error bytes.*/ + uint32_t usr_data_fail: 1; /*0: Means no failure and that the data of user data is reliable 1: Means that programming user data failed and the number of error bytes is over 6.*/ + uint32_t key1_err_num: 3; /*The value of this signal means the number of error bytes.*/ + uint32_t key0_fail: 1; /*0: Means no failure and that the data of key0 is reliable 1: Means that programming key0 failed and the number of error bytes is over 6.*/ + uint32_t key2_err_num: 3; /*The value of this signal means the number of error bytes.*/ + uint32_t key1_fail: 1; /*0: Means no failure and that the data of key1 is reliable 1: Means that programming key1 failed and the number of error bytes is over 6.*/ + uint32_t key3_err_num: 3; /*The value of this signal means the number of error bytes.*/ + uint32_t key2_fail: 1; /*0: Means no failure and that the data of key2 is reliable 1: Means that programming key2 failed and the number of error bytes is over 6.*/ + uint32_t key4_err_num: 3; /*The value of this signal means the number of error bytes.*/ + uint32_t key3_fail: 1; /*0: Means no failure and that the data of key3 is reliable 1: Means that programming key3 failed and the number of error bytes is over 6.*/ + }; + uint32_t val; + } rd_rs_err0; + union { + struct { + uint32_t key5_err_num: 3; /*The value of this signal means the number of error bytes.*/ + uint32_t key4_fail: 1; /*0: Means no failure and that the data of KEY4 is reliable 1: Means that programming KEY4 failed and the number of error bytes is over 6.*/ + uint32_t sys_part2_err_num: 3; /*The value of this signal means the number of error bytes.*/ + uint32_t key5_fail: 1; /*0: Means no failure and that the data of KEY5 is reliable 1: Means that programming KEY5 failed and the number of error bytes is over 6.*/ + uint32_t reserved8: 24; /*Reserved.*/ + }; + uint32_t val; + } rd_rs_err1; + union { + struct { + uint32_t mem_force_pd: 1; /*Set this bit to force eFuse SRAM into power-saving mode.*/ + uint32_t mem_clk_force_on: 1; /*Set this bit and force to activate clock signal of eFuse SRAM.*/ + uint32_t mem_force_pu: 1; /*Set this bit to force eFuse SRAM into working mode.*/ + uint32_t reserved3: 13; /*Reserved.*/ + uint32_t clk_en: 1; /*Set this bit and force to enable clock signal of eFuse memory.*/ + uint32_t reserved17: 15; /*Reserved.*/ + }; + uint32_t val; + } clk; + union { + struct { + uint32_t op_code: 16; /*0x5A5A: Operate programming command 0x5AA5: Operate read command.*/ + uint32_t reserved16:16; /*Reserved.*/ + }; + uint32_t val; + } conf; + union { + struct { + uint32_t state: 4; /*Indicates the state of the eFuse state machine.*/ + uint32_t otp_load_sw: 1; /*The value of OTP_LOAD_SW.*/ + uint32_t otp_vddq_c_sync2: 1; /*The value of OTP_VDDQ_C_SYNC2.*/ + uint32_t otp_strobe_sw: 1; /*The value of OTP_STROBE_SW.*/ + uint32_t otp_csb_sw: 1; /*The value of OTP_CSB_SW.*/ + uint32_t otp_pgenb_sw: 1; /*The value of OTP_PGENB_SW.*/ + uint32_t otp_vddq_is_sw: 1; /*The value of OTP_VDDQ_IS_SW.*/ + uint32_t repeat_err_cnt: 8; /*Indicates the number of error bits during programming BLOCK0.*/ + uint32_t reserved18: 14; /*Reserved.*/ + }; + uint32_t val; + } status; + union { + struct { + uint32_t read_cmd: 1; /*Set this bit to send read command.*/ + uint32_t pgm_cmd: 1; /*Set this bit to send programming command.*/ + uint32_t blk_num: 4; /*The serial number of the block to be programmed. Value 0-10 corresponds to block number 0-10 respectively.*/ + uint32_t reserved6: 26; /*Reserved.*/ + }; + uint32_t val; + } cmd; + union { + struct { + uint32_t read_done: 1; /*The raw bit signal for read_done interrupt.*/ + uint32_t pgm_done: 1; /*The raw bit signal for pgm_done interrupt.*/ + uint32_t reserved2: 30; /*Reserved.*/ + }; + uint32_t val; + } int_raw; + union { + struct { + uint32_t read_done: 1; /*The status signal for read_done interrupt.*/ + uint32_t pgm_done: 1; /*The status signal for pgm_done interrupt.*/ + uint32_t reserved2: 30; /*Reserved.*/ + }; + uint32_t val; + } int_st; + union { + struct { + uint32_t read_done: 1; /*The enable signal for read_done interrupt.*/ + uint32_t pgm_done: 1; /*The enable signal for pgm_done interrupt.*/ + uint32_t reserved2: 30; /*Reserved.*/ + }; + uint32_t val; + } int_ena; + union { + struct { + uint32_t read_done: 1; /*The clear signal for read_done interrupt.*/ + uint32_t pgm_done: 1; /*The clear signal for pgm_done interrupt.*/ + uint32_t reserved2: 30; /*Reserved.*/ + }; + uint32_t val; + } int_clr; + union { + struct { + uint32_t dac_clk_div: 8; /*Controls the division factor of the rising clock of the programming voltage.*/ + uint32_t dac_clk_pad_sel: 1; /*Don't care.*/ + uint32_t dac_num: 8; /*Controls the rising period of the programming voltage.*/ + uint32_t oe_clr: 1; /*Reduces the power supply of the programming voltage.*/ + uint32_t reserved18: 14; /*Reserved.*/ + }; + uint32_t val; + } dac_conf; + union { + struct { + uint32_t reserved0: 24; /*Configures the setup time of read operation.*/ + uint32_t read_init_num: 8; /*Configures the initial read time of eFuse.*/ + }; + uint32_t val; + } rd_tim_conf; + union { + struct { + uint32_t reserved0: 8; /*Configures the setup time of programming operation.*/ + uint32_t pwr_on_num:16; /*Configures the power up time for VDDQ.*/ + uint32_t reserved24: 8; /*Reserved.*/ + }; + uint32_t val; + } wr_tim_conf1; + union { + struct { + uint32_t pwr_off_num:16; /*Configures the power outage time for VDDQ.*/ + uint32_t reserved16: 16; /*Reserved.*/ + }; + uint32_t val; + } wr_tim_conf2; + uint32_t reserved_1f8; + union { + struct { + uint32_t date: 28; /*Stores eFuse version.*/ + uint32_t reserved28: 4; /*Reserved.*/ + }; + uint32_t val; + } date; + uint32_t dbg_erase_all; +} __attribute__((packed)); + +typedef struct ESP32C3EfuseRegs ESP32C3EfuseRegs; + +typedef struct ESP32C3EfuseState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + /* In case no block was given by the user, use the mirror as a file in RAM */ + BlockBackend *blk; + void* mirror; + + qemu_irq irq; + /* Use a mirror to make sure the operation value did not change between the moment + * it is scheduled and the moment it actually happens. */ + uint32_t op_cmd_mirror; + QEMUTimer op_timer; + + ESP32C3EfuseRegs efuses; +} ESP32C3EfuseState; + + +/** + * Define a few helpers for the efuse blocks + */ + +/** + * Returns the size of the given block, in bytes. + * BLOCK0 and BLOCK1 have 6 registers while other blocks have 8 registers + */ +static inline int esp32c3_efuse_block_size(const uint32_t block) +{ + return (block == 0 || block == 1) ? ESP32C3_EFUSE_BLOCK0_WORDS * sizeof(uint32_t) + : 8 * sizeof(uint32_t); +} + +/** + * Returns true if the current command is a valid read command, false else + */ +static inline bool esp32c3_efuse_is_read_cmd(ESP32C3EfuseState *s) +{ + return s->efuses.conf.op_code == EFUSE_READ_OPCODE && s->efuses.cmd.read_cmd; +} + +/** + * Returns true if the current command is a valid write/program command, false else + */ +static inline bool esp32c3_efuse_is_write_cmd(ESP32C3EfuseState *s) +{ + return s->efuses.conf.op_code == EFUSE_WRITE_OPCODE && s->efuses.cmd.pgm_cmd; +} diff --git a/include/hw/riscv/esp32c3_clk.h b/include/hw/riscv/esp32c3_clk.h new file mode 100644 index 000000000000..8a8d5bea7e8d --- /dev/null +++ b/include/hw/riscv/esp32c3_clk.h @@ -0,0 +1,295 @@ +/* + * ESP32-C3 CPU Clock and Reset + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/esp32c3_reg.h" + +#define TYPE_ESP32C3_CLOCK "esp32c3.soc.clk" +#define ESP32C3_CLOCK(obj) OBJECT_CHECK(ESP32C3ClockState, (obj), TYPE_ESP32C3_CLOCK) + + +#define ESP32C3_SYSTEM_CPU_INTR_COUNT 4 + +/** + * Value for SYSTEM_SOC_CLK_SEL + */ +#define ESP32C3_CLK_SEL_XTAL 0 +#define ESP32C3_CLK_SEL_PLL 1 +#define ESP32C3_CLK_SEL_RCFAST 2 + +/** + * Values for SYSTEM_PLL_FREQ_SEL + */ +#define ESP32C3_FREQ_SEL_PLL_480 0 +#define ESP32C3_FREQ_SEL_PLL_320 1 + +/** + * Values for SYSTEM_CPUPERIOD_SEL +*/ +#define ESP32C3_PERIOD_SEL_80 0 +#define ESP32C3_PERIOD_SEL_160 1 + + +typedef struct ESP32C3ClockState { + SysBusDevice parent_obj; + MemoryRegion iomem; + + /* Registers for clocks configuration and frequency dividers */ + uint32_t cpuperconf; + uint32_t sysclk; + + + /* IRQs for crosscore interrupts */ + qemu_irq irqs[ESP32C3_SYSTEM_CPU_INTR_COUNT]; + + /* Bitmap that keeps the level of the IRQs */ + uint32_t levels; +} ESP32C3ClockState; + + +REG32(SYSTEM_CPU_PERI_CLK_EN, 0x000) + FIELD(SYSTEM_CPU_PERI_CLK_EN, CLK_EN_DEDICATED_GPIO, 7, 1) + FIELD(SYSTEM_CPU_PERI_CLK_EN, CLK_EN_ASSIST_DEBUG, 6, 1) + +REG32(SYSTEM_CPU_PERI_RST_EN, 0x004) + FIELD(SYSTEM_CPU_PERI_RST_EN, RST_EN_DEDICATED_GPIO, 7, 1) + FIELD(SYSTEM_CPU_PERI_RST_EN, RST_EN_ASSIST_DEBUG, 6, 1) + +REG32(SYSTEM_CPU_PER_CONF, 0x008) + FIELD(SYSTEM_CPU_PER_CONF, CPU_WAITI_DELAY_NUM, 4, 4) + FIELD(SYSTEM_CPU_PER_CONF, CPU_WAIT_MODE_FORCE_ON, 3, 1) + FIELD(SYSTEM_CPU_PER_CONF, PLL_FREQ_SEL, 2, 1) + FIELD(SYSTEM_CPU_PER_CONF, CPUPERIOD_SEL, 0, 2) + +REG32(SYSTEM_MEM_PD_MASK, 0x00C) + FIELD(SYSTEM_MEM_PD_MASK, LSLP_MEM_PD_MASK, 0, 1) + +REG32(SYSTEM_PERIP_CLK_EN0, 0x010) + FIELD(SYSTEM_PERIP_CLK_EN0, SPI4_CLK_EN, 31, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, ADC2_ARB_CLK_EN, 30, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, SYSTIMER_CLK_EN, 29, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, APB_SARADC_CLK_EN, 28, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, SPI3_DMA_CLK_EN, 27, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, PWM3_CLK_EN, 26, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, PWM2_CLK_EN, 25, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, UART_MEM_CLK_EN, 24, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, USB_DEVICE_CLK_EN, 23, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, SPI2_DMA_CLK_EN, 22, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, I2S1_CLK_EN, 21, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, PWM1_CLK_EN, 20, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, CAN_CLK_EN, 19, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, EXT1_CLK_EN, 18, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, PWM0_CLK_EN, 17, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, SPI3_CLK_EN, 16, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, TIMERGROUP1_CLK_EN, 15, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, EFUSE_CLK_EN, 14, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, TIMERGROUP_CLK_EN, 13, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, UHCI1_CLK_EN, 12, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, LEDC_CLK_EN, 11, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, PCNT_CLK_EN, 10, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, RMT_CLK_EN, 9, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, UHCI0_CLK_EN, 8, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, EXT0_CLK_EN, 7, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, SPI2_CLK_EN, 6, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, UART1_CLK_EN, 5, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, I2S0_CLK_EN, 4, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, WDG_CLK_EN, 3, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, UART_CLK_EN, 2, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, SPI01_CLK_EN, 1, 1) + FIELD(SYSTEM_PERIP_CLK_EN0, TIMERS_CLK_EN, 0, 1) + +REG32(SYSTEM_PERIP_CLK_EN1, 0x014) + FIELD(SYSTEM_PERIP_CLK_EN1, TSENS_CLK_EN, 10, 1) + FIELD(SYSTEM_PERIP_CLK_EN1, UART2_CLK_EN, 9, 1) + FIELD(SYSTEM_PERIP_CLK_EN1, LCD_CAM_CLK_EN, 8, 1) + FIELD(SYSTEM_PERIP_CLK_EN1, SDIO_HOST_CLK_EN, 7, 1) + FIELD(SYSTEM_PERIP_CLK_EN1, DMA_CLK_EN, 6, 1) + FIELD(SYSTEM_PERIP_CLK_EN1, CRYPTO_HMAC_CLK_EN, 5, 1) + FIELD(SYSTEM_PERIP_CLK_EN1, CRYPTO_DS_CLK_EN, 4, 1) + FIELD(SYSTEM_PERIP_CLK_EN1, CRYPTO_RSA_CLK_EN, 3, 1) + FIELD(SYSTEM_PERIP_CLK_EN1, CRYPTO_SHA_CLK_EN, 2, 1) + FIELD(SYSTEM_PERIP_CLK_EN1, CRYPTO_AES_CLK_EN, 1, 1) + +REG32(SYSTEM_PERIP_RST_EN0, 0x018) + FIELD(SYSTEM_PERIP_RST_EN0, SPI4_RST, 31, 1) + FIELD(SYSTEM_PERIP_RST_EN0, ADC2_ARB_RST, 30, 1) + FIELD(SYSTEM_PERIP_RST_EN0, SYSTIMER_RST, 29, 1) + FIELD(SYSTEM_PERIP_RST_EN0, APB_SARADC_RST, 28, 1) + FIELD(SYSTEM_PERIP_RST_EN0, SPI3_DMA_RST, 27, 1) + FIELD(SYSTEM_PERIP_RST_EN0, PWM3_RST, 26, 1) + FIELD(SYSTEM_PERIP_RST_EN0, PWM2_RST, 25, 1) + FIELD(SYSTEM_PERIP_RST_EN0, UART_MEM_RST, 24, 1) + FIELD(SYSTEM_PERIP_RST_EN0, USB_DEVICE_RST, 23, 1) + FIELD(SYSTEM_PERIP_RST_EN0, SPI2_DMA_RST, 22, 1) + FIELD(SYSTEM_PERIP_RST_EN0, I2S1_RST, 21, 1) + FIELD(SYSTEM_PERIP_RST_EN0, PWM1_RST, 20, 1) + FIELD(SYSTEM_PERIP_RST_EN0, CAN_RST, 19, 1) + FIELD(SYSTEM_PERIP_RST_EN0, EXT1_RST, 18, 1) + FIELD(SYSTEM_PERIP_RST_EN0, PWM0_RST, 17, 1) + FIELD(SYSTEM_PERIP_RST_EN0, SPI3_RST, 16, 1) + FIELD(SYSTEM_PERIP_RST_EN0, TIMERGROUP1_RST, 15, 1) + FIELD(SYSTEM_PERIP_RST_EN0, EFUSE_RST, 14, 1) + FIELD(SYSTEM_PERIP_RST_EN0, TIMERGROUP_RST, 13, 1) + FIELD(SYSTEM_PERIP_RST_EN0, UHCI1_RST, 12, 1) + FIELD(SYSTEM_PERIP_RST_EN0, LEDC_RST, 11, 1) + FIELD(SYSTEM_PERIP_RST_EN0, PCNT_RST, 10, 1) + FIELD(SYSTEM_PERIP_RST_EN0, RMT_RST, 9, 1) + FIELD(SYSTEM_PERIP_RST_EN0, UHCI0_RST, 8, 1) + FIELD(SYSTEM_PERIP_RST_EN0, EXT0_RST, 7, 1) + FIELD(SYSTEM_PERIP_RST_EN0, SPI2_RST, 6, 1) + FIELD(SYSTEM_PERIP_RST_EN0, UART1_RST, 5, 1) + FIELD(SYSTEM_PERIP_RST_EN0, I2S0_RST, 4, 1) + FIELD(SYSTEM_PERIP_RST_EN0, WDG_RST, 3, 1) + FIELD(SYSTEM_PERIP_RST_EN0, UART_RST, 2, 1) + FIELD(SYSTEM_PERIP_RST_EN0, SPI01_RST, 1, 1) + FIELD(SYSTEM_PERIP_RST_EN0, TIMERS_RST, 0, 1) + +REG32(SYSTEM_PERIP_RST_EN1, 0x01C) + FIELD(SYSTEM_PERIP_RST_EN1, TSENS_RST, 10, 1) + FIELD(SYSTEM_PERIP_RST_EN1, UART2_RST, 9, 1) + FIELD(SYSTEM_PERIP_RST_EN1, LCD_CAM_RST, 8, 1) + FIELD(SYSTEM_PERIP_RST_EN1, SDIO_HOST_RST, 7, 1) + FIELD(SYSTEM_PERIP_RST_EN1, DMA_RST, 6, 1) + FIELD(SYSTEM_PERIP_RST_EN1, CRYPTO_HMAC_RST, 5, 1) + FIELD(SYSTEM_PERIP_RST_EN1, CRYPTO_DS_RST, 4, 1) + FIELD(SYSTEM_PERIP_RST_EN1, CRYPTO_RSA_RST, 3, 1) + FIELD(SYSTEM_PERIP_RST_EN1, CRYPTO_SHA_RST, 2, 1) + FIELD(SYSTEM_PERIP_RST_EN1, CRYPTO_AES_RST, 1, 1) + +REG32(SYSTEM_BT_LPCK_DIV_INT, 0x020) + FIELD(SYSTEM_BT_LPCK_DIV_INT, BT_LPCK_DIV_NUM, 0, 12) + +REG32(SYSTEM_BT_LPCK_DIV_FRAC, 0x024) + FIELD(SYSTEM_BT_LPCK_DIV_FRAC, LPCLK_RTC_EN, 28, 1) + FIELD(SYSTEM_BT_LPCK_DIV_FRAC, LPCLK_SEL_XTAL32K, 27, 1) + FIELD(SYSTEM_BT_LPCK_DIV_FRAC, LPCLK_SEL_XTAL, 26, 1) + FIELD(SYSTEM_BT_LPCK_DIV_FRAC, LPCLK_SEL_8M, 25, 1) + FIELD(SYSTEM_BT_LPCK_DIV_FRAC, LPCLK_SEL_RTC_SLOW, 24, 1) + FIELD(SYSTEM_BT_LPCK_DIV_FRAC, BT_LPCK_DIV_A, 12, 12) + FIELD(SYSTEM_BT_LPCK_DIV_FRAC, BT_LPCK_DIV_B, 0, 12) + +REG32(SYSTEM_CPU_INTR_FROM_CPU_0, 0x028) + FIELD(SYSTEM_CPU_INTR_FROM_CPU_0, CPU_INTR_FROM_CPU_0, 0, 1) + +REG32(SYSTEM_CPU_INTR_FROM_CPU_1, 0x02C) + FIELD(SYSTEM_CPU_INTR_FROM_CPU_1, CPU_INTR_FROM_CPU_1, 0, 1) + +REG32(SYSTEM_CPU_INTR_FROM_CPU_2, 0x030) + FIELD(SYSTEM_CPU_INTR_FROM_CPU_2, CPU_INTR_FROM_CPU_2, 0, 1) + +REG32(SYSTEM_CPU_INTR_FROM_CPU_3, 0x034) + FIELD(SYSTEM_CPU_INTR_FROM_CPU_3, CPU_INTR_FROM_CPU_3, 0, 1) + +REG32(SYSTEM_RSA_PD_CTRL, 0x038) + FIELD(SYSTEM_RSA_PD_CTRL, RSA_MEM_FORCE_PD, 2, 1) + FIELD(SYSTEM_RSA_PD_CTRL, RSA_MEM_FORCE_PU, 1, 1) + FIELD(SYSTEM_RSA_PD_CTRL, RSA_MEM_PD, 0, 1) + +REG32(SYSTEM_EDMA_CTRL, 0x03C) + FIELD(SYSTEM_EDMA_CTRL, EDMA_RESET, 1, 1) + FIELD(SYSTEM_EDMA_CTRL, EDMA_CLK_ON, 0, 1) + +REG32(SYSTEM_CACHE_CONTROL, 0x040) + FIELD(SYSTEM_CACHE_CONTROL, DCACHE_RESET, 3, 1) + FIELD(SYSTEM_CACHE_CONTROL, DCACHE_CLK_ON, 2, 1) + FIELD(SYSTEM_CACHE_CONTROL, ICACHE_RESET, 1, 1) + FIELD(SYSTEM_CACHE_CONTROL, ICACHE_CLK_ON, 0, 1) + +REG32(SYSTEM_EXTERNAL_DEVICE_ENCRYPT_DECRYPT_CONTROL, 0x044) + FIELD(SYSTEM_EXTERNAL_DEVICE_ENCRYPT_DECRYPT_CONTROL, ENABLE_DOWNLOAD_MANUAL_ENCRYPT, 3, 1) + FIELD(SYSTEM_EXTERNAL_DEVICE_ENCRYPT_DECRYPT_CONTROL, ENABLE_DOWNLOAD_G0CB_DECRYPT, 2, 1) + FIELD(SYSTEM_EXTERNAL_DEVICE_ENCRYPT_DECRYPT_CONTROL, ENABLE_DOWNLOAD_DB_ENCRYPT, 1, 1) + FIELD(SYSTEM_EXTERNAL_DEVICE_ENCRYPT_DECRYPT_CONTROL, ENABLE_SPI_MANUAL_ENCRYPT, 0, 1) + +REG32(SYSTEM_RTC_FASTMEM_CONFIG, 0x048) + FIELD(SYSTEM_RTC_FASTMEM_CONFIG, RTC_MEM_CRC_FINISH, 31, 1) + FIELD(SYSTEM_RTC_FASTMEM_CONFIG, RTC_MEM_CRC_LEN, 20, 11) + FIELD(SYSTEM_RTC_FASTMEM_CONFIG, RTC_MEM_CRC_ADDR, 9, 11) + FIELD(SYSTEM_RTC_FASTMEM_CONFIG, RTC_MEM_CRC_START, 8, 1) + +REG32(SYSTEM_RTC_FASTMEM_CRC, 0x04C) + FIELD(SYSTEM_RTC_FASTMEM_CRC, RTC_MEM_CRC_RES, 0, 32) + +REG32(SYSTEM_REDUNDANT_ECO_CTRL, 0x050) + FIELD(SYSTEM_REDUNDANT_ECO_CTRL, REDUNDANT_ECO_RESULT, 1, 1) + FIELD(SYSTEM_REDUNDANT_ECO_CTRL, REDUNDANT_ECO_DRIVE, 0, 1) + +REG32(SYSTEM_CLOCK_GATE, 0x054) + FIELD(SYSTEM_CLOCK_GATE, CLK_EN, 0, 1) + +REG32(SYSTEM_SYSCLK_CONF, 0x058) + FIELD(SYSTEM_SYSCLK_CONF, CLK_DIV_EN, 19, 1) + FIELD(SYSTEM_SYSCLK_CONF, CLK_XTAL_FREQ, 12, 7) + FIELD(SYSTEM_SYSCLK_CONF, SOC_CLK_SEL, 10, 2) + FIELD(SYSTEM_SYSCLK_CONF, PRE_DIV_CNT, 0, 10) + +REG32(SYSTEM_MEM_PVT, 0x05C) + FIELD(SYSTEM_MEM_PVT, MEM_VT_SEL, 22, 2) + FIELD(SYSTEM_MEM_PVT, MEM_TIMING_ERR_CNT, 6, 16) + FIELD(SYSTEM_MEM_PVT, MEM_PVT_MONITOR_EN, 5, 1) + FIELD(SYSTEM_MEM_PVT, MEM_ERR_CNT_CLR, 4, 1) + FIELD(SYSTEM_MEM_PVT, MEM_PATH_LEN, 0, 4) + +REG32(SYSTEM_COMB_PVT_LVT_CONF, 0x060) + FIELD(SYSTEM_COMB_PVT_LVT_CONF, COMB_PVT_MONITOR_EN_LVT, 6, 1) + FIELD(SYSTEM_COMB_PVT_LVT_CONF, COMB_ERR_CNT_CLR_LVT, 5, 1) + FIELD(SYSTEM_COMB_PVT_LVT_CONF, COMB_PATH_LEN_LVT, 0, 5) + +REG32(SYSTEM_COMB_PVT_NVT_CONF, 0x064) + FIELD(SYSTEM_COMB_PVT_NVT_CONF, COMB_PVT_MONITOR_EN_NVT, 6, 1) + FIELD(SYSTEM_COMB_PVT_NVT_CONF, COMB_ERR_CNT_CLR_NVT, 5, 1) + FIELD(SYSTEM_COMB_PVT_NVT_CONF, COMB_PATH_LEN_NVT, 0, 5) + +REG32(SYSTEM_COMB_PVT_HVT_CONF, 0x068) + FIELD(SYSTEM_COMB_PVT_HVT_CONF, COMB_PVT_MONITOR_EN_HVT, 6, 1) + FIELD(SYSTEM_COMB_PVT_HVT_CONF, COMB_ERR_CNT_CLR_HVT, 5, 1) + FIELD(SYSTEM_COMB_PVT_HVT_CONF, COMB_PATH_LEN_HVT, 0, 5) + +REG32(SYSTEM_COMB_PVT_ERR_LVT_SITE0, 0x06C) + FIELD(SYSTEM_COMB_PVT_ERR_LVT_SITE0, COMB_TIMING_ERR_CNT_LVT_SITE0, 0, 16) + +REG32(SYSTEM_COMB_PVT_ERR_NVT_SITE0, 0x070) + FIELD(SYSTEM_COMB_PVT_ERR_NVT_SITE0, COMB_TIMING_ERR_CNT_NVT_SITE0, 0, 16) + +REG32(SYSTEM_COMB_PVT_ERR_HVT_SITE0, 0x074) + FIELD(SYSTEM_COMB_PVT_ERR_HVT_SITE0, COMB_TIMING_ERR_CNT_HVT_SITE0, 0, 16) + +REG32(SYSTEM_COMB_PVT_ERR_LVT_SITE1, 0x078) + FIELD(SYSTEM_COMB_PVT_ERR_LVT_SITE1, COMB_TIMING_ERR_CNT_LVT_SITE1, 0, 16) + +REG32(SYSTEM_COMB_PVT_ERR_NVT_SITE1, 0x07C) + FIELD(SYSTEM_COMB_PVT_ERR_NVT_SITE1, COMB_TIMING_ERR_CNT_NVT_SITE1, 0, 16) + +REG32(SYSTEM_COMB_PVT_ERR_HVT_SITE1, 0x080) + FIELD(SYSTEM_COMB_PVT_ERR_HVT_SITE1, COMB_TIMING_ERR_CNT_HVT_SITE1, 0, 16) + +REG32(SYSTEM_COMB_PVT_ERR_LVT_SITE2, 0x084) + FIELD(SYSTEM_COMB_PVT_ERR_LVT_SITE2, COMB_TIMING_ERR_CNT_LVT_SITE2, 0, 16) + +REG32(SYSTEM_COMB_PVT_ERR_NVT_SITE2, 0x088) + FIELD(SYSTEM_COMB_PVT_ERR_NVT_SITE2, COMB_TIMING_ERR_CNT_NVT_SITE2, 0, 16) + +REG32(SYSTEM_COMB_PVT_ERR_HVT_SITE2, 0x08C) + FIELD(SYSTEM_COMB_PVT_ERR_HVT_SITE2, COMB_TIMING_ERR_CNT_HVT_SITE2, 0, 16) + +REG32(SYSTEM_COMB_PVT_ERR_LVT_SITE3, 0x090) + FIELD(SYSTEM_COMB_PVT_ERR_LVT_SITE3, COMB_TIMING_ERR_CNT_LVT_SITE3, 0, 16) + +REG32(SYSTEM_COMB_PVT_ERR_NVT_SITE3, 0x094) + FIELD(SYSTEM_COMB_PVT_ERR_NVT_SITE3, COMB_TIMING_ERR_CNT_NVT_SITE3, 0, 16) + +REG32(SYSTEM_COMB_PVT_ERR_HVT_SITE3, 0x098) + FIELD(SYSTEM_COMB_PVT_ERR_HVT_SITE3, COMB_TIMING_ERR_CNT_HVT_SITE3, 0, 16) + +REG32(SYSTEM_SYSTEM_DATE, 0xFFC) + FIELD(SYSTEM_SYSTEM_DATE, SYSTEM_REG_DATE, 0, 28) diff --git a/include/hw/riscv/esp32c3_intmatrix.h b/include/hw/riscv/esp32c3_intmatrix.h new file mode 100644 index 000000000000..c822f8228be3 --- /dev/null +++ b/include/hw/riscv/esp32c3_intmatrix.h @@ -0,0 +1,160 @@ +/* + * ESP32-C3 Interrupt Matrix + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#pragma once + +#include "hw/riscv/riscv_hart.h" +#include "target/riscv/esp_cpu.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/esp32c3_reg.h" + + +/** + * Number of inputs in the C3's Interrupt Matrix + */ +#define ESP32C3_INT_MATRIX_INPUTS 62 + +/** + * Name of the output lines of the Interrupt Matrix (that shall be connected to the CPU) + */ +#define ESP32C3_INT_MATRIX_OUTPUT_NAME "misc.esp32c3.intmatrix.out_irqs" + +/** + * Number of CPU peripheral interrupts on the C3. + * This can be considered the output of the interrupt matrix. + */ +#define ESP32C3_CPU_INT_COUNT (ESP_CPU_INT_LINES) + +#define TYPE_ESP32C3_INTMATRIX "misc.esp32c3.intmatrix" +#define ESP32C3_INTMATRIX(obj) OBJECT_CHECK(ESP32C3IntMatrixState, (obj), TYPE_ESP32C3_INTMATRIX) + +/** + * Size of the I/O region, in bytes, of the C3 Interrupt Matrix + */ +#define ESP32C3_INTMATRIX_IO_SIZE (0x800) + + +/** + * Index where priority registers start + */ +#define ESP32C3_INTMATRIX_IO_PRIO_START (0x118 / sizeof(uint32_t)) + +#define ESP32C3_INTMATRIX_IO_PRIO_END (0x190 / sizeof(uint32_t)) + +/** + * The following registers are not part of any "register table", contrarily + * to the priorities or mapping. + */ +#define ESP32C3_INTMATRIX_IO_ENABLE_REG (0x104 / sizeof(uint32_t)) + +#define ESP32C3_INTMATRIX_IO_TYPE_REG (0x108 / sizeof(uint32_t)) + +#define ESP32C3_INTMATRIX_IO_THRESH_REG (0x194 / sizeof(uint32_t)) + + +/* Bit value for the type of interrupt trigger */ +#define ESP322C3_INTMATRIX_TRIG_LEVEL 0 +#define ESP322C3_INTMATRIX_TRIG_EDGE 1 + +typedef struct ESP32C3IntMatrixState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + uint8_t irq_map[ESP32C3_INT_MATRIX_INPUTS]; + /* In the following fields, "interrupts" refer to the CPU lines (31) + * and not the peripheral source. */ + /* ESP32-C3 CPU has 31 interrupts numbered from 1 to 31 */ + uint8_t irq_prio[ESP32C3_CPU_INT_COUNT + 1]; + /* Current priority threshold of the CPU interrupts */ + uint8_t irq_thres; + /* Keep a bitmap of the pending interrupts */ + uint64_t irq_pending; + /* Bitmap that records the enabled/disabled interrupts */ + uint64_t irq_enabled; + /* Bitmap that records the type of trigger for interrupts */ + uint64_t irq_trigger; + + /* Fast mirror to access IRQ levels */ + uint64_t irq_levels; + EspRISCVCPU *cpu; + + /* Output IRQ used to notify the CPU, indexed from 1 to 31, so allocate one more */ + qemu_irq out_irqs[ESP32C3_CPU_INT_COUNT + 1]; +} ESP32C3IntMatrixState; + +_Static_assert(sizeof(uint64_t) * 8 >= ESP32C3_INT_MATRIX_INPUTS, + "A single 64-bit value must be able to represent a bitmap of all the interrupt sources"); + +typedef enum { + ETS_WIFI_MAC_INTR_SOURCE = 0, /**< interrupt of WiFi MAC, level*/ + ETS_WIFI_MAC_NMI_SOURCE, /**< interrupt of WiFi MAC, NMI, use if MAC have bug to fix in NMI*/ + ETS_WIFI_PWR_INTR_SOURCE, /**< */ + ETS_WIFI_BB_INTR_SOURCE, /**< interrupt of WiFi BB, level, we can do some calibartion*/ + ETS_BT_MAC_INTR_SOURCE, /**< will be cancelled*/ + ETS_BT_BB_INTR_SOURCE, /**< interrupt of BT BB, level*/ + ETS_BT_BB_NMI_SOURCE, /**< interrupt of BT BB, NMI, use if BB have bug to fix in NMI*/ + ETS_RWBT_INTR_SOURCE, /**< interrupt of RWBT, level*/ + ETS_RWBLE_INTR_SOURCE, /**< interrupt of RWBLE, level*/ + ETS_RWBT_NMI_SOURCE, /**< interrupt of RWBT, NMI, use if RWBT have bug to fix in NMI*/ + ETS_RWBLE_NMI_SOURCE, /**< interrupt of RWBLE, NMI, use if RWBT have bug to fix in NMI*/ + ETS_I2C_MASTER_SOURCE, /**< interrupt of I2C Master, level*/ + ETS_SLC0_INTR_SOURCE, /**< interrupt of SLC0, level*/ + ETS_SLC1_INTR_SOURCE, /**< interrupt of SLC1, level*/ + ETS_APB_CTRL_INTR_SOURCE, /**< interrupt of APB ctrl, ?*/ + ETS_UHCI0_INTR_SOURCE, /**< interrupt of UHCI0, level*/ + ETS_GPIO_INTR_SOURCE, /**< interrupt of GPIO, level*/ + ETS_GPIO_NMI_SOURCE, /**< interrupt of GPIO, NMI*/ + ETS_SPI1_INTR_SOURCE, /**< interrupt of SPI1, level, SPI1 is for flash read/write, do not use this*/ + ETS_SPI2_INTR_SOURCE, /**< interrupt of SPI2, level*/ + ETS_I2S1_INTR_SOURCE, /**< interrupt of I2S1, level*/ + ETS_UART0_INTR_SOURCE, /**< interrupt of UART0, level*/ + ETS_UART1_INTR_SOURCE, /**< interrupt of UART1, level*/ + ETS_LEDC_INTR_SOURCE, /**< interrupt of LED PWM, level*/ + ETS_EFUSE_INTR_SOURCE, /**< interrupt of efuse, level, not likely to use*/ + ETS_TWAI_INTR_SOURCE, /**< interrupt of can, level*/ + ETS_USB_SERIAL_JTAG_INTR_SOURCE, /**< interrupt of USJ, level*/ + ETS_RTC_CORE_INTR_SOURCE, /**< interrupt of rtc core, level, include rtc watchdog*/ + ETS_RMT_INTR_SOURCE, /**< interrupt of remote controller, level*/ + ETS_I2C_EXT0_INTR_SOURCE, /**< interrupt of I2C controller1, level*/ + ETS_TIMER1_INTR_SOURCE, + ETS_TIMER2_INTR_SOURCE, + ETS_TG0_T0_LEVEL_INTR_SOURCE, /**< interrupt of TIMER_GROUP0, TIMER0, level*/ + ETS_TG0_WDT_LEVEL_INTR_SOURCE, /**< interrupt of TIMER_GROUP0, WATCH DOG, level*/ + ETS_TG1_T0_LEVEL_INTR_SOURCE, /**< interrupt of TIMER_GROUP1, TIMER0, level*/ + ETS_TG1_WDT_LEVEL_INTR_SOURCE, /**< interrupt of TIMER_GROUP1, WATCHDOG, level*/ + ETS_CACHE_IA_INTR_SOURCE, /**< interrupt of Cache Invalid Access, LEVEL*/ + ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE, /**< interrupt of system timer 0, EDGE*/ + ETS_SYSTIMER_TARGET1_EDGE_INTR_SOURCE, /**< interrupt of system timer 1, EDGE*/ + ETS_SYSTIMER_TARGET2_EDGE_INTR_SOURCE, /**< interrupt of system timer 2, EDGE*/ + ETS_SPI_MEM_REJECT_CACHE_INTR_SOURCE, /**< interrupt of SPI0 Cache access and SPI1 access rejected, LEVEL*/ + ETS_ICACHE_PRELOAD0_INTR_SOURCE, /**< interrupt of ICache per load operation, LEVEL*/ + ETS_ICACHE_SYNC0_INTR_SOURCE, /**< interrupt of instruction cache sync done, LEVEL*/ + ETS_APB_ADC_INTR_SOURCE, /**< interrupt of APB ADC, LEVEL*/ + ETS_DMA_CH0_INTR_SOURCE, /**< interrupt of general DMA channel 0, LEVEL*/ + ETS_DMA_CH1_INTR_SOURCE, /**< interrupt of general DMA channel 1, LEVEL*/ + ETS_DMA_CH2_INTR_SOURCE, /**< interrupt of general DMA channel 2, LEVEL*/ + ETS_RSA_INTR_SOURCE, /**< interrupt of RSA accelerator, level*/ + ETS_AES_INTR_SOURCE, /**< interrupt of AES accelerator, level*/ + ETS_SHA_INTR_SOURCE, /**< interrupt of SHA accelerator, level*/ + ETS_FROM_CPU_INTR0_SOURCE, /**< interrupt0 generated from a CPU, level*/ /* Used for FreeRTOS */ + ETS_FROM_CPU_INTR1_SOURCE, /**< interrupt1 generated from a CPU, level*/ /* Used for FreeRTOS */ + ETS_FROM_CPU_INTR2_SOURCE, /**< interrupt2 generated from a CPU, level*/ + ETS_FROM_CPU_INTR3_SOURCE, /**< interrupt3 generated from a CPU, level*/ + ETS_ASSIST_DEBUG_INTR_SOURCE, /**< interrupt of Assist debug module, LEVEL*/ + ETS_DMA_APBPERI_PMS_INTR_SOURCE, + ETS_CORE0_IRAM0_PMS_INTR_SOURCE, + ETS_CORE0_DRAM0_PMS_INTR_SOURCE, + ETS_CORE0_PIF_PMS_INTR_SOURCE, + ETS_CORE0_PIF_PMS_SIZE_INTR_SOURCE, + ETS_BAK_PMS_VIOLATE_INTR_SOURCE, + ETS_CACHE_CORE0_ACS_INTR_SOURCE, + ETS_MAX_INTR_SOURCE, +} periph_interrupt_t; diff --git a/include/hw/sd/dwc_sdmmc.h b/include/hw/sd/dwc_sdmmc.h new file mode 100644 index 000000000000..6520e6db4c10 --- /dev/null +++ b/include/hw/sd/dwc_sdmmc.h @@ -0,0 +1,60 @@ +/* + * Designware SD/MMC controller emulation + * + * Copyright (c) 2021 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DWC_SDMMC_H +#define DWC_SDMMC_H + +#include "qom/object.h" +#include "hw/sysbus.h" +#include "hw/sd/sd.h" + + +typedef struct DWCSDMMCState { + /*< private >*/ + SysBusDevice busdev; + + /*< public >*/ + SDBus sdbus; + MemoryRegion iomem; + qemu_irq irq; + + uint32_t ctrl; + uint32_t cmd; + uint32_t cmdarg; + uint32_t resp[4]; + uint32_t intmask; + uint32_t rintsts; + uint32_t dbaddr; + uint32_t dscaddr; + uint32_t blksiz; + uint32_t bytcnt; + uint32_t pldmnd; + uint32_t idinten; + uint32_t idsts; + + size_t bytes_left; + + +} DWCSDMMCState; + +#define TYPE_DWC_SDMMC "dwc_sdmmc" +#define DWC_SDMMC(obj) OBJECT_CHECK(DWCSDMMCState, (obj), \ + TYPE_DWC_SDMMC) + +#endif /* DWC_SDMMC_H */ diff --git a/include/hw/ssi/esp32_spi.h b/include/hw/ssi/esp32_spi.h new file mode 100644 index 000000000000..dcf9bc88d2d4 --- /dev/null +++ b/include/hw/ssi/esp32_spi.h @@ -0,0 +1,94 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "hw/ssi/ssi.h" + +#define TYPE_ESP32_SPI "ssi.esp32.spi" +#define ESP32_SPI(obj) OBJECT_CHECK(Esp32SpiState, (obj), TYPE_ESP32_SPI) + +#define ESP32_SPI_CS_COUNT 3 +#define ESP32_SPI_BUF_WORDS 16 + +typedef struct Esp32SpiState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + qemu_irq irq; + qemu_irq cs_gpio[ESP32_SPI_CS_COUNT]; + int num_cs; + SSIBus *spi; + + uint32_t addr_reg; + uint32_t ctrl_reg; + uint32_t status_reg; + uint32_t ctrl1_reg; + uint32_t ctrl2_reg; + uint32_t user_reg; + uint32_t user1_reg; + uint32_t user2_reg; + uint32_t mosi_dlen_reg; + uint32_t miso_dlen_reg; + uint32_t pin_reg; + uint32_t data_reg[ESP32_SPI_BUF_WORDS]; +} Esp32SpiState; + + +REG32(SPI_CMD, 0x00) + FIELD(SPI_CMD, READ, 31, 1) + FIELD(SPI_CMD, WREN, 30, 1) + FIELD(SPI_CMD, WRDI, 29, 1) + FIELD(SPI_CMD, RDID, 28, 1) + FIELD(SPI_CMD, RDSR, 27, 1) + FIELD(SPI_CMD, WRSR, 26, 1) + FIELD(SPI_CMD, PP, 25, 1) + FIELD(SPI_CMD, SE, 24, 1) + FIELD(SPI_CMD, BE, 23, 1) + FIELD(SPI_CMD, CE, 22, 1) + FIELD(SPI_CMD, DP, 21, 1) + FIELD(SPI_CMD, RES, 20, 1) + FIELD(SPI_CMD, HPM, 19, 1) + FIELD(SPI_CMD, USR, 18, 1) + FIELD(SPI_CMD, PES, 17, 1) + FIELD(SPI_CMD, PER, 16, 1) + +REG32(SPI_ADDR, 0x04) +REG32(SPI_CTRL, 0x08) +REG32(SPI_STATUS, 0x10) + FIELD(SPI_STATUS, STATUS, 0, 16) + +REG32(SPI_CTRL1, 0x0c) +REG32(SPI_CTRL2, 0x14) +REG32(SPI_USER, 0x1C) + FIELD(SPI_USER, COMMAND, 31, 1) + FIELD(SPI_USER, ADDR, 30, 1) + FIELD(SPI_USER, DUMMY, 29, 1) + FIELD(SPI_USER, MISO, 28, 1) + FIELD(SPI_USER, MOSI, 27, 1) + FIELD(SPI_USER, SIO, 16, 1) + FIELD(SPI_USER, DOUTDIN, 0, 1) + +REG32(SPI_USER1, 0x20) + FIELD(SPI_USER1, ADDR_BITLEN, 26, 6) + FIELD(SPI_USER1, DUMMY_CYCLELEN, 0, 8) + +REG32(SPI_USER2, 0x24) + FIELD(SPI_USER2, COMMAND_BITLEN, 28, 4) + FIELD(SPI_USER2, COMMAND_VALUE, 0, 16) + +REG32(SPI_MOSI_DLEN, 0x28) +REG32(SPI_MISO_DLEN, 0x2c) +REG32(SPI_PIN, 0x34) +REG32(SPI_SLAVE, 0x38) + FIELD(SPI_SLAVE, TRANS_DONE, 4, 1) + FIELD(SPI_SLAVE, TRANS_INTEN, 9, 1) + FIELD(SPI_SLAVE, TRANS_CNT, 22, 4) + FIELD(SPI_SLAVE, SLAVE_MODE, 30, 1) + +REG32(SPI_W0, 0x80) +REG32(SPI_EXT0, 0xF0) +REG32(SPI_EXT1, 0xF4) +REG32(SPI_EXT2, 0xF8) +REG32(SPI_EXT3, 0xFC) + + diff --git a/include/hw/ssi/esp32c3_spi.h b/include/hw/ssi/esp32c3_spi.h new file mode 100644 index 000000000000..14b64af25050 --- /dev/null +++ b/include/hw/ssi/esp32c3_spi.h @@ -0,0 +1,271 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "hw/ssi/ssi.h" + +#define TYPE_ESP32C3_SPI "ssi.esp32c3.spi" +#define ESP32C3_SPI(obj) OBJECT_CHECK(ESP32C3SpiState, (obj), TYPE_ESP32C3_SPI) + +/** + * Size of the SPI I/O registers area + */ +#define ESP32C3_SPI_IO_SIZE (A_SPI_MEM_DATE + 4) + + +#define ESP32C3_SPI_BUF_WORDS 16 + +#define ESP32C3_SPI_CS_COUNT 3 + +typedef struct ESP32C3SpiState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + SSIBus *spi; + qemu_irq cs_gpio[ESP32C3_SPI_CS_COUNT]; + + uint32_t mem_cmd; + /** + * In user mode, this register represents the flash address. + * In other modes, bits 0 to 23 included is the memory address and bits 24 to 31 included + * is the number of bytes to process. + */ + uint32_t mem_addr; + uint32_t mem_ctrl; + uint32_t mem_ctrl1; + uint32_t mem_ctrl2; + uint32_t mem_clock; + uint32_t mem_user; + uint32_t mem_user1; + uint32_t mem_user2; + uint32_t mem_miso_len; + uint32_t mem_mosi_len; + uint32_t mem_rd_st; + uint32_t data_reg[ESP32C3_SPI_BUF_WORDS]; + uint32_t mem_sus_st; +} ESP32C3SpiState; + + +REG32(SPI_MEM_CMD, 0x000) + FIELD(SPI_MEM_CMD, FLASH_READ, 31, 1) + FIELD(SPI_MEM_CMD, FLASH_WREN, 30, 1) + FIELD(SPI_MEM_CMD, FLASH_WRDI, 29, 1) + FIELD(SPI_MEM_CMD, FLASH_RDID, 28, 1) + FIELD(SPI_MEM_CMD, FLASH_RDSR, 27, 1) + FIELD(SPI_MEM_CMD, FLASH_WRSR, 26, 1) + FIELD(SPI_MEM_CMD, FLASH_PP, 25, 1) + FIELD(SPI_MEM_CMD, FLASH_SE, 24, 1) + FIELD(SPI_MEM_CMD, FLASH_BE, 23, 1) + FIELD(SPI_MEM_CMD, FLASH_CE, 22, 1) + FIELD(SPI_MEM_CMD, FLASH_DP, 21, 1) + FIELD(SPI_MEM_CMD, FLASH_RES, 20, 1) + FIELD(SPI_MEM_CMD, FLASH_HPM, 19, 1) + FIELD(SPI_MEM_CMD, USR, 18, 1) + FIELD(SPI_MEM_CMD, FLASH_PE, 17, 1) + FIELD(SPI_MEM_CMD, MSPI_ST, 4, 4) + FIELD(SPI_MEM_CMD, SPI1_MST_ST, 0, 4) + +REG32(SPI_MEM_ADDR, 0x004) + FIELD(SPI_MEM_ADDR, USR_ADDR_VALUE, 0, 32) + +REG32(SPI_MEM_CTRL, 0x008) + FIELD(SPI_MEM_CTRL, FREAD_QIO, 24, 1) + FIELD(SPI_MEM_CTRL, FREAD_DIO, 23, 1) + FIELD(SPI_MEM_CTRL, WRSR_2B, 22, 1) + FIELD(SPI_MEM_CTRL, WP_REG, 21, 1) + FIELD(SPI_MEM_CTRL, FREAD_QUAD, 20, 1) + FIELD(SPI_MEM_CTRL, D_POL, 19, 1) + FIELD(SPI_MEM_CTRL, Q_POL, 18, 1) + FIELD(SPI_MEM_CTRL, RESANDRES, 15, 1) + FIELD(SPI_MEM_CTRL, FREAD_DUAL, 14, 1) + FIELD(SPI_MEM_CTRL, FASTRD_MODE, 13, 1) + FIELD(SPI_MEM_CTRL, TX_CRC_EN, 11, 1) + FIELD(SPI_MEM_CTRL, FCS_CRC_EN, 10, 1) + FIELD(SPI_MEM_CTRL, FCMD_QUAD, 8, 1) + FIELD(SPI_MEM_CTRL, FCMD_DUAL, 7, 1) + FIELD(SPI_MEM_CTRL, FDUMMY_OUT, 3, 1) + +REG32(SPI_MEM_CTRL1, 0x00C) + FIELD(SPI_MEM_CTRL1, CS_HOLD_DLY_RES, 2, 10) + FIELD(SPI_MEM_CTRL1, CLK_MODE, 0, 2) + +REG32(SPI_MEM_CTRL2, 0x010) + FIELD(SPI_MEM_CTRL2, SYNC_RESET, 31, 1) + +REG32(SPI_MEM_CLOCK, 0x014) + FIELD(SPI_MEM_CLOCK, CLK_EQU_SYSCLK, 31, 1) + FIELD(SPI_MEM_CLOCK, CLKCNT_N, 16, 8) + FIELD(SPI_MEM_CLOCK, CLKCNT_H, 8, 8) + FIELD(SPI_MEM_CLOCK, CLKCNT_L, 0, 8) + +REG32(SPI_MEM_USER, 0x018) + FIELD(SPI_MEM_USER, USR_COMMAND, 31, 1) + FIELD(SPI_MEM_USER, USR_ADDR, 30, 1) + FIELD(SPI_MEM_USER, USR_DUMMY, 29, 1) + FIELD(SPI_MEM_USER, USR_MISO, 28, 1) + FIELD(SPI_MEM_USER, USR_MOSI, 27, 1) + FIELD(SPI_MEM_USER, USR_DUMMY_IDLE, 26, 1) + FIELD(SPI_MEM_USER, USR_MOSI_HIGHPART, 25, 1) + FIELD(SPI_MEM_USER, USR_MISO_HIGHPART, 24, 1) + FIELD(SPI_MEM_USER, FWRITE_QIO, 15, 1) + FIELD(SPI_MEM_USER, FWRITE_DIO, 14, 1) + FIELD(SPI_MEM_USER, FWRITE_QUAD, 13, 1) + FIELD(SPI_MEM_USER, FWRITE_DUAL, 12, 1) + FIELD(SPI_MEM_USER, CK_OUT_EDGE, 9, 1) + FIELD(SPI_MEM_USER, CS_SETUP, 7, 1) + FIELD(SPI_MEM_USER, CS_HOLD, 6, 1) + +REG32(SPI_MEM_USER1, 0x01C) + FIELD(SPI_MEM_USER1, USR_ADDR_BITLEN, 26, 6) + FIELD(SPI_MEM_USER1, USR_DUMMY_CYCLELEN, 0, 6) + +REG32(SPI_MEM_USER2, 0x020) + FIELD(SPI_MEM_USER2, USR_COMMAND_BITLEN, 28, 4) + FIELD(SPI_MEM_USER2, USR_COMMAND_VALUE, 0, 16) + +REG32(SPI_MEM_MOSI_DLEN, 0x024) + FIELD(SPI_MEM_MOSI_DLEN, USR_MOSI_DBITLEN, 0, 10) + +REG32(SPI_MEM_MISO_DLEN, 0x028) + FIELD(SPI_MEM_MISO_DLEN, USR_MISO_DBITLEN, 0, 10) + +REG32(SPI_MEM_RD_STATUS, 0x02C) + FIELD(SPI_MEM_RD_STATUS, WB_MODE, 16, 8) + FIELD(SPI_MEM_RD_STATUS, STATUS, 0, 16) + +REG32(SPI_MEM_MISC, 0x034) + FIELD(SPI_MEM_MISC, CS_KEEP_ACTIVE, 10, 1) + FIELD(SPI_MEM_MISC, CK_IDLE_EDGE, 9, 1) + FIELD(SPI_MEM_MISC, CS1_DIS, 1, 1) + FIELD(SPI_MEM_MISC, CS0_DIS, 0, 1) + +REG32(SPI_MEM_TX_CRC, 0x038) + FIELD(SPI_MEM_TX_CRC, TX_CRC_DATA, 0, 32) + +REG32(SPI_MEM_CACHE_FCTRL, 0x03C) + FIELD(SPI_MEM_CACHE_FCTRL, FADDR_QUAD, 8, 1) + FIELD(SPI_MEM_CACHE_FCTRL, FDOUT_QUAD, 7, 1) + FIELD(SPI_MEM_CACHE_FCTRL, FDIN_QUAD , 6, 1) + FIELD(SPI_MEM_CACHE_FCTRL, FADDR_DUAL, 5, 1) + FIELD(SPI_MEM_CACHE_FCTRL, FDOUT_DUAL, 4, 1) + FIELD(SPI_MEM_CACHE_FCTRL, FDIN_DUAL , 3, 1) + FIELD(SPI_MEM_CACHE_FCTRL, CACHE_USR_ADDR_4BYTE, 1, 1) + +REG32(SPI_MEM_W0, 0x058) + FIELD(SPI_MEM_W0, BUF0, 0, 32) + +REG32(SPI_MEM_W1, 0x05C) + FIELD(SPI_MEM_W1, BUF1, 0, 32) + +REG32(SPI_MEM_W2, 0x060) + FIELD(SPI_MEM_W2, BUF2, 0, 32) + +REG32(SPI_MEM_W3, 0x064) + FIELD(SPI_MEM_W3, BUF3, 0, 32) + +REG32(SPI_MEM_W4, 0x068) + FIELD(SPI_MEM_W4, BUF4, 0, 32) + +REG32(SPI_MEM_W5, 0x06C) + FIELD(SPI_MEM_W5, BUF5, 0, 32) + +REG32(SPI_MEM_W6, 0x070) + FIELD(SPI_MEM_W6, BUF6, 0, 32) + +REG32(SPI_MEM_W7, 0x074) + FIELD(SPI_MEM_W7, BUF7, 0, 32) + +REG32(SPI_MEM_W8, 0x078) + FIELD(SPI_MEM_W8, BUF8, 0, 32) + +REG32(SPI_MEM_W9, 0x07C) + FIELD(SPI_MEM_W9, BUF9, 0, 32) + +REG32(SPI_MEM_W10, 0x080) + FIELD(SPI_MEM_W10, BUF10, 0, 32) + +REG32(SPI_MEM_W11, 0x084) + FIELD(SPI_MEM_W11, BUF11, 0, 32) + +REG32(SPI_MEM_W12, 0x088) + FIELD(SPI_MEM_W12, BUF12, 0, 32) + +REG32(SPI_MEM_W13, 0x08C) + FIELD(SPI_MEM_W13, BUF13, 0, 32) + +REG32(SPI_MEM_W14, 0x090) + FIELD(SPI_MEM_W14, BUF14, 0, 32) + +REG32(SPI_MEM_W15, 0x094) + FIELD(SPI_MEM_W15, BUF15, 0, 32) + +REG32(SPI_MEM_FLASH_WAITI_CTRL, 0x098) + FIELD(SPI_MEM_FLASH_WAITI_CTRL, WAITI_DUMMY_CYCLELEN, 10, 6) + FIELD(SPI_MEM_FLASH_WAITI_CTRL, WAITI_CMD, 2, 8) + FIELD(SPI_MEM_FLASH_WAITI_CTRL, WAITI_DUMMY, 1, 1) + +REG32(SPI_MEM_FLASH_SUS_CTRL, 0x09C) + FIELD(SPI_MEM_FLASH_SUS_CTRL, SUS_TIMEOUT_CNT, 25, 7) + FIELD(SPI_MEM_FLASH_SUS_CTRL, PES_END_EN, 24, 1) + FIELD(SPI_MEM_FLASH_SUS_CTRL, PER_END_EN, 23, 1) + FIELD(SPI_MEM_FLASH_SUS_CTRL, SPI_FMEM_RD_SUS_2B, 22, 1) + FIELD(SPI_MEM_FLASH_SUS_CTRL, PESR_END_MSK, 6, 16) + FIELD(SPI_MEM_FLASH_SUS_CTRL, FLASH_PES_EN, 5, 1) + FIELD(SPI_MEM_FLASH_SUS_CTRL, PES_PER_EN, 4, 1) + FIELD(SPI_MEM_FLASH_SUS_CTRL, FLASH_PES_WAIT_EN, 3, 1) + FIELD(SPI_MEM_FLASH_SUS_CTRL, FLASH_PER_WAIT_EN, 2, 1) + FIELD(SPI_MEM_FLASH_SUS_CTRL, FLASH_PES, 1, 1) + FIELD(SPI_MEM_FLASH_SUS_CTRL, FLASH_PER, 0, 1) + +REG32(SPI_MEM_FLASH_SUS_CMD, 0x0A0) + FIELD(SPI_MEM_FLASH_SUS_CMD, WAIT_PESR_COMMAND, 16, 16) + FIELD(SPI_MEM_FLASH_SUS_CMD, FLASH_PES_COMMAND, 8, 8) + FIELD(SPI_MEM_FLASH_SUS_CMD, FLASH_PER_COMMAND, 0, 8) + +REG32(SPI_MEM_SUS_STATUS, 0x0A4) + FIELD(SPI_MEM_SUS_STATUS, SPI0_LOCK_EN, 7, 1) + FIELD(SPI_MEM_SUS_STATUS, FLASH_PES_DLY_128, 6, 1) + FIELD(SPI_MEM_SUS_STATUS, FLASH_PER_DLY_128, 5, 1) + FIELD(SPI_MEM_SUS_STATUS, FLASH_DP_DLY_128, 4, 1) + FIELD(SPI_MEM_SUS_STATUS, FLASH_RES_DLY_128, 3, 1) + FIELD(SPI_MEM_SUS_STATUS, FLASH_HPM_DLY_128, 2, 1) + FIELD(SPI_MEM_SUS_STATUS, WAIT_PESR_CMD_2B, 1, 1) + FIELD(SPI_MEM_SUS_STATUS, FLASH_SUS, 0, 1) + +REG32(SPI_MEM_TIMING_CALI, 0x0A8) + FIELD(SPI_MEM_TIMING_CALI, EXTRA_DUMMY_CYCLELEN, 2, 3) + FIELD(SPI_MEM_TIMING_CALI, TIMING_CALI, 1, 1) + +REG32(SPI_MEM_INT_ENA, 0x0C0) + FIELD(SPI_MEM_INT_ENA, MST_ST_END_INT_ENA, 4, 1) + FIELD(SPI_MEM_INT_ENA, SLV_ST_END_INT_ENA, 3, 1) + FIELD(SPI_MEM_INT_ENA, WPE_END_INT_ENA, 2, 1) + FIELD(SPI_MEM_INT_ENA, PES_END_INT_ENA, 1, 1) + FIELD(SPI_MEM_INT_ENA, PER_END_INT_ENA, 0, 1) + +REG32(SPI_MEM_INT_CLR, 0x0C4) + FIELD(SPI_MEM_INT_CLR, MST_ST_END_INT_CLR, 4, 1) + FIELD(SPI_MEM_INT_CLR, SLV_ST_END_INT_CLR, 3, 1) + FIELD(SPI_MEM_INT_CLR, WPE_END_INT_CLR, 2, 1) + FIELD(SPI_MEM_INT_CLR, PES_END_INT_CLR, 1, 1) + FIELD(SPI_MEM_INT_CLR, PER_END_INT_CLR, 0, 1) + +REG32(SPI_MEM_INT_RAW, 0x0C8) + FIELD(SPI_MEM_INT_RAW, MST_ST_END_INT_RAW, 4, 1) + FIELD(SPI_MEM_INT_RAW, SLV_ST_END_INT_RAW, 3, 1) + FIELD(SPI_MEM_INT_RAW, WPE_END_INT_RAW, 2, 1) + FIELD(SPI_MEM_INT_RAW, PES_END_INT_RAW, 1, 1) + FIELD(SPI_MEM_INT_RAW, PER_END_INT_RAW, 0, 1) + +REG32(SPI_MEM_INT_ST, 0x0CC) + FIELD(SPI_MEM_INT_ST, MST_ST_END_INT_ST, 4, 1) + FIELD(SPI_MEM_INT_ST, SLV_ST_END_INT_ST, 3, 1) + FIELD(SPI_MEM_INT_ST, WPE_END_INT_ST, 2, 1) + FIELD(SPI_MEM_INT_ST, PES_END_INT_ST, 1, 1) + FIELD(SPI_MEM_INT_ST, PER_END_INT_ST, 0, 1) + +REG32(SPI_MEM_CLOCK_GATE, 0x0DC) + FIELD(SPI_MEM_CLOCK_GATE, CLK_EN, 0, 1) + +REG32(SPI_MEM_DATE, 0x3FC) + FIELD(SPI_MEM_DATE, DATE, 0, 28) diff --git a/include/hw/timer/esp32_frc_timer.h b/include/hw/timer/esp32_frc_timer.h new file mode 100644 index 000000000000..cdb09b4cf0d7 --- /dev/null +++ b/include/hw/timer/esp32_frc_timer.h @@ -0,0 +1,49 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "hw/sysbus.h" +#include "hw/misc/esp32_reg.h" + +#define TYPE_ESP32_FRC_TIMER "timer.esp32.frc" +#define ESP32_FRC_TIMER(obj) OBJECT_CHECK(Esp32FrcTimerState, (obj), TYPE_ESP32_FRC_TIMER) + +typedef struct Esp32FrcTimerState { + /* private */ + SysBusDevice parent_obj; + + MemoryRegion iomem; + qemu_irq irq; + QEMUTimer alarm_timer; + + /* properties */ + uint32_t apb_freq; + bool has_alarm; + uint32_t count_mask; + + /* state */ + uint32_t count_base; + uint64_t ns_base; + bool level_int_status; + + /* registers */ + uint32_t load_reg; + bool enable; + bool autoload; + uint32_t prescaler; + bool level_int; + uint32_t alarm_reg; +} Esp32FrcTimerState; + +REG32(FRC_TIMER_LOAD, 0x00) +REG32(FRC_TIMER_COUNT, 0x04) +REG32(FRC_TIMER_CTRL, 0x08) + FIELD(FRC_TIMER_CTRL, LEVEL_INT, 0, 1) + FIELD(FRC_TIMER_CTRL, PRESCALER, 1, 3) + FIELD(FRC_TIMER_CTRL, AUTOLOAD, 6, 1) + FIELD(FRC_TIMER_CTRL, ENABLE, 7, 1) + FIELD(FRC_TIMER_CTRL, STATUS, 8, 1) +REG32(FRC_TIMER_INT_CLR, 0x0c) +REG32(FRC_TIMER_ALARM, 0x10) + +#define ESP32_FRC_TIMER_STRIDE 0x20 diff --git a/include/hw/timer/esp32_timg.h b/include/hw/timer/esp32_timg.h new file mode 100644 index 000000000000..dbf554ae120b --- /dev/null +++ b/include/hw/timer/esp32_timg.h @@ -0,0 +1,217 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/registerfields.h" + +#define TYPE_ESP32_TIMG "timer.esp32.timg" +#define ESP32_TIMG(obj) OBJECT_CHECK(Esp32TimgState, (obj), TYPE_ESP32_TIMG) + +#define ESP32_TIMG_WDT_STAGE_COUNT 4 + +typedef enum Esp32TimgCalClkSel { + ESP32_TIMG_CAL_RTC_MUX = 0, + ESP32_TIMG_CAL_8MD256 = 1, + ESP32_TIMG_CAL_32K_XTAL = 2 +} Esp32TimgCalClkSel; + +typedef enum Esp32TimgInterruptType { + TIMG_T0_INT, + TIMG_T1_INT, + TIMG_WDT_INT, + TIMG_LACT_INT, + TIMG_INT_MAX +} Esp32TimgInterruptType; + +typedef struct Esp32TimgState Esp32TimgState; + +typedef struct Esp32TimgTimerState { + Esp32TimgState *parent; + uint32_t config_reg; + int divider; + bool en; + bool autoreload; + bool inc; + bool edge_int_en; + bool level_int_en; + bool alarm; + uint64_t alarm_val; + uint64_t load_val; + uint64_t count_base; + uint64_t last_val; + uint64_t ns_base; + Esp32TimgInterruptType int_type; + QEMUTimer alarm_timer; +} Esp32TimgTimerState; + +typedef enum Esp32TimgWdtStageMode { + WDT_MODE_OFF = 0, + WDT_MODE_INT = 1, + WDT_MODE_CPURESET = 2, + WDT_MODE_SYSRESET = 3 +} Esp32TimgWdtStageMode; + +typedef struct Esp32TimgWdtState { + Esp32TimgState *parent; + uint32_t config0_reg; + uint32_t config1_reg; + bool en; + bool flashboot_en; + bool level_int_en; + bool edge_int_en; + int prescale; + Esp32TimgWdtStageMode mode[ESP32_TIMG_WDT_STAGE_COUNT]; + int timeout[ESP32_TIMG_WDT_STAGE_COUNT]; + uint32_t count_base; + uint64_t ns_base; + int cur_stage; + uint32_t protect_reg; + QEMUTimer stage_timer; +} Esp32TimgWdtState; + +typedef struct Esp32TimgState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + int id; + qemu_irq irqs[2*TIMG_INT_MAX]; + qemu_irq wdt_cpu_reset_req; + qemu_irq wdt_sys_reset_req; + + Esp32TimgTimerState t0; + Esp32TimgTimerState t1; + Esp32TimgTimerState lact; + Esp32TimgWdtState wdt; + + uint32_t int_ena; + uint32_t int_raw; + + uint32_t rtc_slow_freq_hz; + uint32_t xtal_freq_hz; + uint32_t apb_freq_hz; + bool flash_boot_mode; + bool wdt_en_at_reset; + bool wdt_disable; + + bool rtc_cal_start; + bool rtc_cal_ready; + Esp32TimgCalClkSel rtc_cal_clk_sel; + uint32_t rtc_cal_max; + uint32_t rtc_cal_value; +} Esp32TimgState; + +#define ESP32_TIMG_WDT_CPU_RESET_GPIO "mwdt-cpu-reset" +#define ESP32_TIMG_WDT_SYS_RESET_GPIO "mwdt-sys-reset" + +#define RTC_CLK_CAL_FRACT 19 +#define RTC_CLK_CAL_FACTOR (1 << RTC_CLK_CAL_FRACT) + +REG32(TIMG_T0CONFIG, 0x00) + FIELD(TIMG_T0CONFIG, EN, 31, 1) + FIELD(TIMG_T0CONFIG, INCREASE, 30, 1) + FIELD(TIMG_T0CONFIG, AUTORELOAD, 29, 1) + FIELD(TIMG_T0CONFIG, DIVIDER, 13, 16) + FIELD(TIMG_T0CONFIG, EDGE_INT, 12, 1) + FIELD(TIMG_T0CONFIG, LEVEL_INT, 11, 1) + FIELD(TIMG_T0CONFIG, ALARM, 10, 1) + +REG32(TIMG_T0LO, 0x04) +REG32(TIMG_T0HI, 0x08) +REG32(TIMG_T0UPDATE, 0x0c) +REG32(TIMG_T0ALARMLO, 0x10) +REG32(TIMG_T0ALARMHI, 0x14) +REG32(TIMG_T0LOADLO, 0x18) +REG32(TIMG_T0LOADHI, 0x1c) +REG32(TIMG_T0LOAD, 0x20) + +REG32(TIMG_T1CONFIG, 0x24) + FIELD(TIMG_T1CONFIG, EN, 31, 1) + FIELD(TIMG_T1CONFIG, INCREASE, 30, 1) + FIELD(TIMG_T1CONFIG, AUTORELOAD, 29, 1) + FIELD(TIMG_T1CONFIG, DIVIDER, 13, 16) + FIELD(TIMG_T1CONFIG, EDGE_INT, 12, 1) + FIELD(TIMG_T1CONFIG, LEVEL_INT, 11, 1) + FIELD(TIMG_T1CONFIG, ALARM, 10, 1) + +REG32(TIMG_T1LO, 0x28) +REG32(TIMG_T1HI, 0x2c) +REG32(TIMG_T1UPDATE, 0x30) +REG32(TIMG_T1ALARMLO, 0x34) +REG32(TIMG_T1ALARMHI, 0x38) +REG32(TIMG_T1LOADLO, 0x3c) +REG32(TIMG_T1LOADHI, 0x40) +REG32(TIMG_T1LOAD, 0x44) + +REG32(TIMG_WDTCONFIG0, 0x48) + FIELD(TIMG_WDTCONFIG0, EN, 31, 1) + FIELD(TIMG_WDTCONFIG0, STG0, 29, 2) + FIELD(TIMG_WDTCONFIG0, STG1, 27, 2) + FIELD(TIMG_WDTCONFIG0, STG2, 25, 2) + FIELD(TIMG_WDTCONFIG0, STG3, 23, 2) + FIELD(TIMG_WDTCONFIG0, EDGE_INT, 22, 1) + FIELD(TIMG_WDTCONFIG0, LEVEL_INT, 21, 1) + FIELD(TIMG_WDTCONFIG0, FLASHBOOT_MODE_EN, 14, 1) +REG32(TIMG_WDTCONFIG1, 0x4c) + FIELD(TIMG_WDTCONFIG1, PRESCALE, 16, 16) +REG32(TIMG_WDTCONFIG2, 0x50) +REG32(TIMG_WDTCONFIG3, 0x54) +REG32(TIMG_WDTCONFIG4, 0x58) +REG32(TIMG_WDTCONFIG5, 0x5c) +REG32(TIMG_WDTFEED, 0x60) + FIELD(TIMG_WDTFEED, FEED, 31, 1) +REG32(TIMG_WDTPROTECT, 0x64) + + +REG32(TIMG_RTCCALICFG, 0x68) + FIELD(TIMG_RTCCALICFG, START, 31, 1) + FIELD(TIMG_RTCCALICFG, MAX, 16, 15) + FIELD(TIMG_RTCCALICFG, RDY, 15, 1) + FIELD(TIMG_RTCCALICFG, CLK_SEL, 13, 2) + FIELD(TIMG_RTCCALICFG, START_CYCLING, 12, 1) + +REG32(TIMG_RTCCALICFG1, 0x6c) + FIELD(TIMG_RTCCALICFG1, VALUE, 7, 25) + +REG32(TIMG_LACTCONFIG, 0x70) + FIELD(TIMG_LACTCONFIG, EN, 31, 1) + FIELD(TIMG_LACTCONFIG, INCREASE, 30, 1) + FIELD(TIMG_LACTCONFIG, AUTORELOAD, 29, 1) + FIELD(TIMG_LACTCONFIG, DIVIDER, 13, 16) + FIELD(TIMG_LACTCONFIG, EDGE_INT, 12, 1) + FIELD(TIMG_LACTCONFIG, LEVEL_INT, 11, 1) + FIELD(TIMG_LACTCONFIG, ALARM, 10, 1) +REG32(TIMG_LACTRTC, 0x74) + FIELD(TIMG_LACTRTC, STEP_LEN, 6, 26) +REG32(TIMG_LACTLO, 0x78) +REG32(TIMG_LACTHI, 0x7c) +REG32(TIMG_LACTUPDATE, 0x80) +REG32(TIMG_LACTALARMLO, 0x84) +REG32(TIMG_LACTALARMHI, 0x88) +REG32(TIMG_LACTLOADLO, 0x8c) +REG32(TIMG_LACTLOADHI, 0x90) +REG32(TIMG_LACTLOAD, 0x94) + +REG32(TIMG_INT_ENA, 0x98) + FIELD(TIMG_INT_ENA, LACT, 3, 1) + FIELD(TIMG_INT_ENA, WDT, 2, 1) + FIELD(TIMG_INT_ENA, T1, 1, 1) + FIELD(TIMG_INT_ENA, T0, 0, 1) + +REG32(TIMG_INT_RAW, 0x9c) + FIELD(TIMG_INT_RAW, LACT, 3, 1) + FIELD(TIMG_INT_RAW, WDT, 2, 1) + FIELD(TIMG_INT_RAW, T1, 1, 1) + FIELD(TIMG_INT_RAW, T0, 0, 1) + +REG32(TIMG_INT_ST, 0xa0) + FIELD(TIMG_INT_ST, LACT, 3, 1) + FIELD(TIMG_INT_ST, WDT, 2, 1) + FIELD(TIMG_INT_ST, T1, 1, 1) + FIELD(TIMG_INT_ST, T0, 0, 1) + +REG32(TIMG_INT_CLR, 0xa4) + FIELD(TIMG_INT_CLR, LACT, 3, 1) + FIELD(TIMG_INT_CLR, WDT, 2, 1) + FIELD(TIMG_INT_CLR, T1, 1, 1) + FIELD(TIMG_INT_CLR, T0, 0, 1) + +#define ESP32_TIMG_WDT_PROTECT_WORD 0x50D83AA1 diff --git a/include/hw/timer/esp32c3_systimer.h b/include/hw/timer/esp32c3_systimer.h new file mode 100644 index 000000000000..495930fb8ba0 --- /dev/null +++ b/include/hw/timer/esp32c3_systimer.h @@ -0,0 +1,231 @@ +/* + * ESP32-C3 System Timer emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#pragma once + +#include "hw/hw.h" +#include "hw/registerfields.h" + + +#define TYPE_ESP32C3_SYSTIMER "esp32c3.systimer" +#define ESP32C3_SYSTIMER(obj) OBJECT_CHECK(ESP32C3SysTimerState, (obj), TYPE_ESP32C3_SYSTIMER) +#define ESP32C3_SYSTIMER_GET_CLASS(obj) OBJECT_GET_CLASS(ESP32C3SysTimerState, obj, TYPE_ESP32C3_SYSTIMER) +#define ESP32C3_SYSTIMER_CLASS(klass) OBJECT_CLASS_CHECK(ESP32C3SysTimerState, klass, TYPE_ESP32C3_SYSTIMER) + + +/** + * Size of the System Timer I/O registers area + */ +#define ESP32C3_SYSTIMER_IO_SIZE (A_SYSTIMER_DATE + 4) + +/** + * Mask to get a 52 value out of a 64 bit value + */ +#define ESP32C3_SYSTIMER_52BIT_MASK ((1ULL << 52) - 1) + +/** + * Frequency of the CNT_CLK + */ +#define ESP32C3_SYSTIMER_CNT_CLK 16000000 + +/** + * Ticks per microsecond + */ +#define ESP32C3_SYSTIMER_CNT_PER_US (ESP32C3_SYSTIMER_CNT_CLK / 1000000) + +/** + * Macro to help updating part of a register/variable + */ +static inline void systimer_set_reg(uint64_t* reg, uint64_t value, uint64_t mask, uint64_t shift) +{ + const uint64_t new_val = (value & mask) << shift; + *reg = (*reg & ~(mask << shift)) | new_val; +} + +#define SYSTIMER_GET_REG(reg, shift, mask) (((reg) >> (shift)) & (mask)) + +/** + * Number of comparator in a single System Timer module + */ +#define ESP32C3_SYSTIMER_COMP_COUNT 3 + +/** + * Number of counters in a single System Time module + */ +#define ESP32C3_SYSTIMER_COUNTER_COUNT 2 + +/** + * Number of interrupt line of the System Time module + */ +#define ESP32C3_SYSTIMER_IRQ_COUNT (ESP32C3_SYSTIMER_COMP_COUNT) + + +typedef struct { + bool enabled; + /* Enabled on CPU stall */ + bool enabled_on_stall; + uint64_t value; // Internal counter that should be updated as often as possible + uint64_t toload; // Counter that can be loaded by the guest program + uint64_t flushed; // Mirror of the internal counter that can be seen by the guest program + /* Absolute time, in ns, when value was updated last */ + int64_t base; +} ESP32C3SysTimerCounter; + + +/* This typedef must be placed here as it will be used by the structure below */ +typedef struct ESP32C3SysTimerState ESP32C3SysTimerState; + +typedef struct { + uint64_t value; + uint64_t value_toload; + uint32_t period; + uint32_t period_toload; + /* Mark whether the comparator is enabled */ + bool enabled; + bool period_mode; + /* Raw status of the comparator: 1 if it reached the threshold, 0 else */ + bool raw_st; + bool int_enabled; + /* Index of the counter that is linked to the comparator */ + uint32_t counter; + /* The easiest way to implement timeout is by using one timer per comparator */ + QEMUTimer qtimer; + uint64_t expire_time; + qemu_irq irq; + int cur_irq_level; + /* Pointer to the owner */ + ESP32C3SysTimerState* systimer; +} ESP32C3SysTimerComp; + + +struct ESP32C3SysTimerState { + SysBusDevice parent_obj; + MemoryRegion iomem; + /* Mirror of the comparators and counters state, only used to speed up + * reading of A_SYSTIMER_CONF register */ + uint32_t conf; + ESP32C3SysTimerCounter counter[ESP32C3_SYSTIMER_COUNTER_COUNT]; + ESP32C3SysTimerComp comparators[ESP32C3_SYSTIMER_COMP_COUNT]; +}; + + +REG32(SYSTIMER_CONF, 0x0000) + FIELD(SYSTIMER_CONF, CLK_EN, 31, 1) + FIELD(SYSTIMER_CONF, TIMER_UNIT0_WORK_EN, 30, 1) + FIELD(SYSTIMER_CONF, TIMER_UNIT1_WORK_EN, 29, 1) + FIELD(SYSTIMER_CONF, TIMER_UNIT0_CORE0_STALL_EN, 28, 1) + FIELD(SYSTIMER_CONF, TIMER_UNIT0_CORE1_STALL_EN, 27, 1) + FIELD(SYSTIMER_CONF, TIMER_UNIT1_CORE0_STALL_EN, 26, 1) + FIELD(SYSTIMER_CONF, TIMER_UNIT1_CORE1_STALL_EN, 25, 1) + FIELD(SYSTIMER_CONF, TARGET0_WORK_EN, 24, 1) + FIELD(SYSTIMER_CONF, TARGET1_WORK_EN, 23, 1) + FIELD(SYSTIMER_CONF, TARGET2_WORK_EN, 22, 1) + +REG32(SYSTIMER_UNIT0_OP, 0x0004) + FIELD(SYSTIMER_UNIT0_OP, UPDATE, 30, 1) + FIELD(SYSTIMER_UNIT0_OP, VALUE_VALID, 29, 1) + +REG32(SYSTIMER_UNIT1_OP, 0x0008) + FIELD(SYSTIMER_UNIT1_OP, UPDATE, 30, 1) + FIELD(SYSTIMER_UNIT1_OP, VALID, 29, 1) + +REG32(SYSTIMER_UNIT0_LOAD_HI, 0x000C) + FIELD(SYSTIMER_UNIT0_LOAD_HI, HI, 0, 20) + +REG32(SYSTIMER_UNIT0_LOAD_LO, 0x0010) + FIELD(SYSTIMER_UNIT0_LOAD_LO, LO, 0, 32) + +REG32(SYSTIMER_UNIT1_LOAD_HI, 0x0014) + FIELD(SYSTIMER_UNIT1_LOAD_HI, HI, 0, 20) + +REG32(SYSTIMER_UNIT1_LOAD_LO, 0x0018) + FIELD(SYSTIMER_UNIT1_LOAD_LO, LO, 0, 32) + +REG32(SYSTIMER_TARGET0_HI, 0x001C) + FIELD(SYSTIMER_TARGET0_HI, HI, 0, 20) + +REG32(SYSTIMER_TARGET0_LO, 0x0020) + FIELD(SYSTIMER_TARGET0_LO, LO, 0, 32) + +REG32(SYSTIMER_TARGET1_HI, 0x0024) + FIELD(SYSTIMER_TARGET1_HI, HI, 0, 20) + +REG32(SYSTIMER_TARGET1_LO, 0x0028) + FIELD(SYSTIMER_TARGET1_LO, LO, 0, 32) + +REG32(SYSTIMER_TARGET2_HI, 0x002C) + FIELD(SYSTIMER_TARGET2_HI, HI, 0, 20) + +REG32(SYSTIMER_TARGET2_LO, 0x0030) + FIELD(SYSTIMER_TARGET2_LO, LO, 0, 32) + +REG32(SYSTIMER_TARGET0_CONF, 0x0034) + FIELD(SYSTIMER_TARGET0_CONF, TIMER_UNIT_SEL, 31, 1) + FIELD(SYSTIMER_TARGET0_CONF, PERIOD_MODE, 30, 1) + FIELD(SYSTIMER_TARGET0_CONF, PERIOD, 0, 26) + +REG32(SYSTIMER_TARGET1_CONF, 0x0038) + FIELD(SYSTIMER_TARGET1_CONF, TIMER_UNIT_SEL, 31, 1) + FIELD(SYSTIMER_TARGET1_CONF, PERIOD_MODE, 30, 1) + FIELD(SYSTIMER_TARGET1_CONF, PERIOD, 0, 26) + +REG32(SYSTIMER_TARGET2_CONF, 0x003C) + FIELD(SYSTIMER_TARGET2_CONF, TIMER_UNIT_SEL, 31, 1) + FIELD(SYSTIMER_TARGET2_CONF, PERIOD_MODE, 30, 1) + FIELD(SYSTIMER_TARGET2_CONF, PERIOD, 0, 26) + +REG32(SYSTIMER_UNIT0_VALUE_HI, 0x0040) + FIELD(SYSTIMER_UNIT0_VALUE_HI, TIMER_HI, 0, 20) + +REG32(SYSTIMER_UNIT0_VALUE_LO, 0x0044) + FIELD(SYSTIMER_UNIT0_VALUE_LO, TIMER_LO, 0, 32) + +REG32(SYSTIMER_UNIT1_VALUE_HI, 0x0048) + FIELD(SYSTIMER_UNIT1_VALUE_HI, TIMER_HI, 0, 20) + +REG32(SYSTIMER_UNIT1_VALUE_LO, 0x004C) + FIELD(SYSTIMER_UNIT1_VALUE_LO, TIMER_LO, 0, 32) + +REG32(SYSTIMER_COMP0_LOAD, 0x0050) + FIELD(SYSTIMER_COMP0_LOAD, LOAD, 0, 1) + +REG32(SYSTIMER_COMP1_LOAD, 0x0054) + FIELD(SYSTIMER_COMP1_LOAD, LOAD, 0, 1) + +REG32(SYSTIMER_COMP2_LOAD, 0x0058) + FIELD(SYSTIMER_COMP2_LOAD, LOAD, 0, 1) + +REG32(SYSTIMER_UNIT0_LOAD, 0x005C) + FIELD(SYSTIMER_UNIT0_LOAD, LOAD, 0, 1) + +REG32(SYSTIMER_UNIT1_LOAD, 0x0060) + FIELD(SYSTIMER_UNIT1_LOAD, LOAD, 0, 1) + +REG32(SYSTIMER_INT_ENA, 0x0064) + FIELD(SYSTIMER_INT_ENA, TARGET2, 2, 1) + FIELD(SYSTIMER_INT_ENA, TARGET1, 1, 1) + FIELD(SYSTIMER_INT_ENA, TARGET0, 0, 1) + +REG32(SYSTIMER_INT_RAW, 0x0068) + FIELD(SYSTIMER_INT_RAW, TARGET2, 2, 1) + FIELD(SYSTIMER_INT_RAW, TARGET1, 1, 1) + FIELD(SYSTIMER_INT_RAW, TARGET0, 0, 1) + +REG32(SYSTIMER_INT_CLR, 0x006c) + FIELD(SYSTIMER_INT_CLR, TARGET2, 2, 1) + FIELD(SYSTIMER_INT_CLR, TARGET1, 1, 1) + FIELD(SYSTIMER_INT_CLR, TARGET0, 0, 1) + +REG32(SYSTIMER_INT_ST, 0x0070) + FIELD(SYSTIMER_INT_ST, TARGET2, 2, 1) + FIELD(SYSTIMER_INT_ST, TARGET1, 1, 1) + FIELD(SYSTIMER_INT_ST, TARGET0, 0, 1) + +REG32(SYSTIMER_DATE, 0x00fc) + FIELD(SYSTIMER_DATE, DATE, 0, 28) diff --git a/include/hw/timer/esp32c3_timg.h b/include/hw/timer/esp32c3_timg.h new file mode 100644 index 000000000000..8a920fd860cd --- /dev/null +++ b/include/hw/timer/esp32c3_timg.h @@ -0,0 +1,255 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/registerfields.h" + + +#define TYPE_ESP32C3_TIMG "esp32c3.timg" +#define ESP32C3_TIMG(obj) OBJECT_CHECK(ESP32C3TimgState, (obj), TYPE_ESP32C3_TIMG) +#define ESP32C3_TIMG_GET_CLASS(obj) OBJECT_GET_CLASS(ESP32C3TimgState, obj, TYPE_ESP32C3_TIMG) +#define ESP32C3_TIMG_CLASS(klass) OBJECT_CLASS_CHECK(ESP32C3TimgState, klass, TYPE_ESP32C3_TIMG) + + +/** + * Size of the Timegroup I/O registers area + */ +#define ESP32C3_TIMG_IO_SIZE (A_TIMGCLK + 4) + +/** + * Values related to the TIMG T0 counter + */ +#define ESP32C3_TIMG_T0_MAX_VALUE ((1ULL << 54) - 1) +/* Limit value is used to calculate the distance between the alarm and the counter */ +#define ESP32C3_TIMG_T0_LIMIT (1ULL << 53) + +/** + * Value of each calibration clock available + */ +#define ESP32C3_TIMG_CALI_RC_SLOW_CLK 0 +#define ESP32C3_TIMG_CALI_RC_FAST_DIV_CLK 1 +#define ESP32C3_TIMG_CALI_XTAL32K_CLK 2 + +/** + * And their associated frequencies + */ +#define ESP32C3_APB_CLK 80000000UL +#define ESP32C3_XTAL_CLK 40000000UL +#define ESP32C3_RC_SLOW_FREQ 136000 +#define ESP32C3_RC_FAST_FREQ 17500000 +#define ESP32C3_RC_FAST_DIV_FREQ (ESP32C3_RC_FAST_FREQ / 256) +#define ESP32C3_XTAL32K_FREQ 32000 + + +/** + * Number of stages in the a single Watchdog timer + */ +#define ESP32C3_WDT_STAGE_COUNT 4 + +/** + * Default key value for the WKEY register. + */ +#define ESP32C3_WDT_DEFAULT_WKEY 0x50d83aa1 + +/** + * Define two names for the WDT's interrupt IRQ and reset IRQ respectively + */ +#define ESP32C3_WDT_IRQ_RESET "wdt-reset" +#define ESP32C3_WDT_IRQ_INTERRUPT "wdt-interrupt" + + +#define ESP32C3_T0_IRQ_INTERRUPT "t0-interrupt" + + +typedef enum { + ESP32C3_WDT_OFF = 0, + ESP32C3_WDT_INTERRUPT = 1, + ESP32C3_WDT_RESET_CPU = 2, + ESP32C3_WDT_RESET_SYS = 3, +} ESP32C3WdtStageConf; + + +typedef struct ESP32C3VirtualCounter { + QEMUTimer timer; + /* Timer current value in ticks */ + uint64_t value; + /* Time when the value was last updated */ + uint64_t base; + /* Frequency, in Hz, of the timer */ + uint64_t frequency; +} ESP32C3VirtualCounter; + + +typedef struct ESP32C3WdtState { + /* Store the configuration register as is, it will ease reads perform to it */ + uint32_t config0; + /* Only keep the prescaler field for the config1 register */ + uint32_t prescaler; + /* Value of each stage, in MWDT clock cycles! (CLK / Prescaler) */ + uint32_t stage[ESP32C3_WDT_STAGE_COUNT]; + /* Value used to protect writes to the registers */ + uint32_t wkey; + /* Raw status of the interrupt */ + int raw_st; + bool int_enabled; + + /* These are mirror values that are written by the software */ + uint32_t prescaler_mirror; + uint32_t stage_mirror[ESP32C3_WDT_STAGE_COUNT]; + + /* "Private" members, not accessible by the software */ + /* Mirror of the stages configuration */ + ESP32C3WdtStageConf stage_conf[ESP32C3_WDT_STAGE_COUNT]; + /* The stage is comprised between 0 and ESP32C3_WDT_STAGE_COUNT */ + int current_stage; + ESP32C3VirtualCounter counter; + qemu_irq reset_irq; + qemu_irq interrupt_irq; +} ESP32C3WdtState; + + +typedef struct ESP32C3T0State { + uint32_t config; + /* Register containing the alarm value */ + uint64_t alarm; + /* Relative value that will be inc/dec according to the configuration */ + uint64_t value_rel; + /* Register containing the current counter value after a flush request */ + uint64_t value_flushed; + /* Register containing the value to copy to the counter */ + uint64_t value_toload; + + /* Raw status of the interrupt */ + int raw_st; + bool int_enabled; + ESP32C3VirtualCounter counter; + qemu_irq interrupt_irq; +} ESP32C3T0State; + + +typedef struct ESP32C3RtcState { + uint32_t rtc_cali_cfg; + /* Register storing the result of calibration (RTCCALICFG1) */ + uint32_t rtc_cali_cfg_result; + /* Register storing the calibration timeout (RTCCALICFG2) */ + uint32_t rtc_cali_cfg_timeout; +} ESP32C3RtcState; + + +typedef struct ESP32C3TimgState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + ESP32C3T0State t0; + ESP32C3WdtState wdt; + ESP32C3RtcState rtc; +} ESP32C3TimgState; + + +REG32(TIMG_T0CONFIG, 0x0000) + FIELD(TIMG_T0CONFIG, EN, 31, 1) + FIELD(TIMG_T0CONFIG, INCREASE, 30, 1) + FIELD(TIMG_T0CONFIG, AUTORELOAD, 29, 1) + FIELD(TIMG_T0CONFIG, DIVIDER, 13, 16) + FIELD(TIMG_T0CONFIG, DIVCNT_RST, 12, 1) + FIELD(TIMG_T0CONFIG, ALARM_EN, 10, 1) + FIELD(TIMG_T0CONFIG, USE_XTAL, 9, 1) + +REG32(TIMG_T0LO, 0x0004) + FIELD(TIMG_T0LO, LO, 0, 32) + +REG32(TIMG_T0HI, 0x0008) + FIELD(TIMG_T0HI, HI, 0, 22) + +REG32(TIMG_T0UPDATE, 0x000c) + FIELD(TIMG_T0UPDATE, UPDATE, 31, 1) + +REG32(TIMG_T0ALARMLO, 0x0010) + FIELD(TIMG_T0ALARMLO, ALARM_LO, 0, 32) + +REG32(TIMG_T0ALARMHI, 0x0014) + FIELD(TIMG_T0ALARMHI, ALARM_HI, 0, 22) + +REG32(TIMG_T0LOADLO, 0x0018) + FIELD(TIMG_T0LOADLO, LOAD_LO, 0, 32) + +REG32(TIMG_T0LOADHI, 0x001c) + FIELD(TIMG_T0LOADHI, LOAD_HI, 0, 22) + +REG32(TIMG_T0LOAD, 0x0020) + FIELD(TIMG_T0LOAD, LOAD, 0, 32) + +REG32(TIMG_WDTCONFIG0, 0x0048) + FIELD(TIMG_WDTCONFIG0, EN, 31, 1) + FIELD(TIMG_WDTCONFIG0, STG0, 29, 2) + FIELD(TIMG_WDTCONFIG0, STG1, 27, 2) + FIELD(TIMG_WDTCONFIG0, STG2, 25, 2) + FIELD(TIMG_WDTCONFIG0, STG3, 23, 2) + FIELD(TIMG_WDTCONFIG0, CONF_UPDATE_EN, 22, 1) + FIELD(TIMG_WDTCONFIG0, USE_XTAL, 21, 1) + FIELD(TIMG_WDTCONFIG0, CPU_RESET_LENGTH, 18, 3) + FIELD(TIMG_WDTCONFIG0, SYS_RESET_LENGTH, 15, 3) + FIELD(TIMG_WDTCONFIG0, FLASHBOOT_MOD_EN, 14, 1) + FIELD(TIMG_WDTCONFIG0, PROCPU_RESET_EN, 13, 1) + FIELD(TIMG_WDTCONFIG0, APPCPU_RESET_EN, 12, 1) + +REG32(TIMG_WDTCONFIG1, 0x004c) + FIELD(TIMG_WDTCONFIG1, CLK_PRESCALE, 16, 16) + FIELD(TIMG_WDTCONFIG1, DIVCNT_RST, 0, 1) + +REG32(TIMG_WDTCONFIG2, 0x0050) + FIELD(TIMG_WDTCONFIG2, STG0_HOLD, 0, 32) + +REG32(TIMG_WDTCONFIG3, 0x0054) + FIELD(TIMG_WDTCONFIG3, STG1_HOLD, 0, 32) + +REG32(TIMG_WDTCONFIG4, 0x0058) + FIELD(TIMG_WDTCONFIG4, STG2_HOLD, 0, 32) + +REG32(TIMG_WDTCONFIG5, 0x005c) + FIELD(TIMG_WDTCONFIG5, STG3_HOLD, 0, 32) + +REG32(TIMG_WDTFEED, 0x0060) + FIELD(TIMG_WDTFEED, FEED, 0, 32) + +REG32(TIMG_WDTWPROTECT, 0x0064) + FIELD(TIMG_WDTWPROTECT, WKEY, 0, 32) + +REG32(TIMG_RTCCALICFG, 0x0068) + FIELD(TIMG_RTCCALICFG, START, 31, 1) + FIELD(TIMG_RTCCALICFG, MAX, 16, 15) + FIELD(TIMG_RTCCALICFG, RDY, 15, 1) + FIELD(TIMG_RTCCALICFG, CLK_SEL, 13, 2) + FIELD(TIMG_RTCCALICFG, START_CYCLING, 12, 1) + +REG32(TIMG_RTCCALICFG1, 0x006c) + FIELD(TIMG_RTCCALICFG1, VALUE, 7, 25) + FIELD(TIMG_RTCCALICFG1, CYCLING_DATA_VLD, 0, 1) + +REG32(TIMG_INT_ENA_TIMG, 0x0070) + FIELD(TIMG_INT_ENA_TIMG, WDT_ENA, 1, 1) + FIELD(TIMG_INT_ENA_TIMG, T0_ENA, 0, 1) + +REG32(TIMG_INT_RAW_TIMG, 0x0074) + FIELD(TIMG_INT_RAW_TIMG, WDT_RAW, 1, 1) + FIELD(TIMG_INT_RAW_TIMG, T0_RAW, 0, 1) + +REG32(TIMG_INT_ST_TIMG, 0x0078) + FIELD(TIMG_INT_ST_TIMG, WDT_ST, 1, 1) + FIELD(TIMG_INT_ST_TIMG, T0_ST, 0, 1) + +REG32(TIMG_INT_CLR_TIMG, 0x007c) + FIELD(TIMG_INT_CLR_TIMG, WDT_CLR, 1, 1) + FIELD(TIMG_INT_CLR_TIMG, T0_CLR, 0, 1) + +REG32(TIMG_RTCCALICFG2, 0x0080) + FIELD(TIMG_RTCCALICFG2, TIMEOUT_THRES, 7, 25) + FIELD(TIMG_RTCCALICFG2, TIMEOUT_RST_CNT, 3, 4) + FIELD(TIMG_RTCCALICFG2, TIMEOUT, 0, 1) + +REG32(TIMG_NTIMG_DATE, 0x00f8) + FIELD(TIMG_NTIMG_DATE, TIMG_NTIMGS_DATE, 0, 28) + +REG32(TIMGCLK, 0x00fc) + FIELD(TIMGCLK, CLK_EN, 31, 1) + FIELD(TIMGCLK, TIMER_CLK_IS_ACTIVE, 30, 1) + FIELD(TIMGCLK, WDT_CLK_IS_ACTIVE, 29, 1) diff --git a/include/hw/xtensa/esp32.h b/include/hw/xtensa/esp32.h new file mode 100644 index 000000000000..261a21669e2c --- /dev/null +++ b/include/hw/xtensa/esp32.h @@ -0,0 +1,71 @@ +#pragma once + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "target/xtensa/cpu.h" +#include "hw/misc/esp32_reg.h" +#include "hw/char/esp32_uart.h" +#include "hw/gpio/esp32_gpio.h" +#include "hw/misc/esp32_dport.h" +#include "hw/misc/esp32_rtc_cntl.h" +#include "hw/misc/esp32_rng.h" +#include "hw/misc/esp32_sha.h" +#include "hw/misc/esp32_aes.h" +#include "hw/misc/esp32_ledc.h" +#include "hw/misc/esp32_rsa.h" +#include "hw/misc/esp32_unknown.h" +#include "hw/misc/esp32_ana.h" +#include "hw/misc/esp32_wifi.h" +#include "hw/misc/esp32_phya.h" +#include "hw/misc/esp32_fe.h" +#include "hw/timer/esp32_frc_timer.h" +#include "hw/timer/esp32_timg.h" +#include "hw/misc/esp32_crosscore_int.h" +#include "hw/ssi/esp32_spi.h" +#include "hw/i2c/esp32_i2c.h" +#include "hw/nvram/esp32_efuse.h" +#include "hw/xtensa/esp32_intc.h" +#include "hw/misc/esp32_flash_enc.h" +#include "hw/sd/dwc_sdmmc.h" + +typedef struct Esp32SocState { + /*< private >*/ + DeviceState parent_obj; + + /*< public >*/ + XtensaCPU cpu[ESP32_CPU_COUNT]; + Esp32DportState dport; + Esp32IntMatrixState intmatrix; + Esp32CrosscoreInt crosscore_int; + ESP32UARTState uart[ESP32_UART_COUNT]; + Esp32GpioState gpio; + Esp32RngState rng; + Esp32RtcCntlState rtc_cntl; + Esp32FrcTimerState frc_timer[ESP32_FRC_COUNT]; + Esp32TimgState timg[ESP32_TIMG_COUNT]; + Esp32SpiState spi[ESP32_SPI_COUNT]; + Esp32I2CState i2c[ESP32_I2C_COUNT]; + Esp32ShaState sha; + Esp32AesState aes; + Esp32RsaState rsa; + Esp32LEDCState ledc; + Esp32EfuseState efuse; + Esp32FlashEncryptionState flash_enc; + Esp32UnknownState unknown; + Esp32AnaState ana; + Esp32WifiState wifi; + Esp32PhyaState phya; + Esp32FeState fe; + + DWCSDMMCState sdmmc; + DeviceState *eth; + DeviceState *wifi_dev; + + + BusState rtc_bus; + BusState periph_bus; + + MemoryRegion cpu_specific_mem[ESP32_CPU_COUNT]; + + uint32_t requested_reset; +} Esp32SocState; diff --git a/include/hw/xtensa/esp32_intc.h b/include/hw/xtensa/esp32_intc.h new file mode 100644 index 000000000000..bd0bb8008c14 --- /dev/null +++ b/include/hw/xtensa/esp32_intc.h @@ -0,0 +1,42 @@ +/* + * ESP32 Interrupt Matrix + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#pragma once + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "target/xtensa/cpu.h" +#include "target/xtensa/cpu-qom.h" + +#define ESP32_CPU_COUNT 2 +#define ESP32_INT_MATRIX_INPUTS 69 + +#define TYPE_ESP32_INTMATRIX "misc.esp32.intmatrix" +#define ESP32_INTMATRIX(obj) OBJECT_CHECK(Esp32IntMatrixState, (obj), TYPE_ESP32_INTMATRIX) + + +typedef struct Esp32IntMatrixState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + qemu_irq *outputs[ESP32_CPU_COUNT]; + uint8_t irq_map[ESP32_CPU_COUNT][ESP32_INT_MATRIX_INPUTS]; + uint8_t irq_raw[ESP32_INT_MATRIX_INPUTS]; + + /* properties */ + XtensaCPU *cpu[ESP32_CPU_COUNT]; +} Esp32IntMatrixState; + diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 5cfaa5393848..333fc437cbb7 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -1190,8 +1190,7 @@ uint64_t dup_const(unsigned vece, uint64_t c); ? ( (VECE) == MO_8 ? 0x0101010101010101ull * (uint8_t)(C) \ : (VECE) == MO_16 ? 0x0001000100010001ull * (uint16_t)(C) \ : (VECE) == MO_32 ? 0x0000000100000001ull * (uint32_t)(C) \ - : (VECE) == MO_64 ? (uint64_t)(C) \ - : (qemu_build_not_reached_always(), 0)) \ + : dup_const(VECE, C)) \ : dup_const(VECE, C)) #if TARGET_LONG_BITS == 64 diff --git a/pc-bios/esp32-v3-rom-app.bin b/pc-bios/esp32-v3-rom-app.bin new file mode 100755 index 000000000000..ea8b05d465b0 Binary files /dev/null and b/pc-bios/esp32-v3-rom-app.bin differ diff --git a/pc-bios/esp32-v3-rom.bin b/pc-bios/esp32-v3-rom.bin new file mode 100755 index 000000000000..1ae597988296 Binary files /dev/null and b/pc-bios/esp32-v3-rom.bin differ diff --git a/pc-bios/esp32c3-rom.bin b/pc-bios/esp32c3-rom.bin new file mode 100755 index 000000000000..853f400d3f03 Binary files /dev/null and b/pc-bios/esp32c3-rom.bin differ diff --git a/pc-bios/keymaps/meson.build b/pc-bios/keymaps/meson.build index 158a3b410c17..1cbcdebefa92 100644 --- a/pc-bios/keymaps/meson.build +++ b/pc-bios/keymaps/meson.build @@ -1,5 +1,5 @@ keymaps = { - 'ar': '-l ar', + 'ar': '-l ara', 'bepo': '-l fr -v dvorak', 'cz': '-l cz', 'da': '-l dk', diff --git a/pc-bios/meson.build b/pc-bios/meson.build index a7224ef4699b..dc699be1609a 100644 --- a/pc-bios/meson.build +++ b/pc-bios/meson.build @@ -56,6 +56,9 @@ blobs = [ 'efi-virtio.rom', 'efi-e1000e.rom', 'efi-vmxnet3.rom', + 'esp32-v3-rom.bin', + 'esp32-v3-rom-app.bin', + 'esp32c3-rom.bin', 'qemu-nsis.bmp', 'bamboo.dtb', 'canyonlands.dtb', diff --git a/target/riscv/esp_cpu.c b/target/riscv/esp_cpu.c new file mode 100644 index 000000000000..a55102e5f648 --- /dev/null +++ b/target/riscv/esp_cpu.c @@ -0,0 +1,316 @@ +/* + * Espressif RISC-V CPU + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/timer.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "sysemu/reset.h" +#include "esp_cpu.h" + + +/* CSR-related */ +#define ESP_CPU_CSR_PCER_M 0x7E0 +#define ESP_CPU_CSR_PCMR_M 0x7E1 +#define ESP_CPU_CSR_MCYCLE_M 0x7E2 + +/* The RISC-V core in QEMU doesn't support the triggers used in ESP32-C3 + * tcontrol is not supported either. So let's override all the debug registers + */ +#define ESP_CPU_CSR_TSELECT 0x7A0 +#define ESP_CPU_CSR_TDATA1 0x7A1 +#define ESP_CPU_CSR_TDATA2 0x7A2 +#define ESP_CPU_CSR_TDATA3 0x7A3 +#define ESP_CPU_CSR_TCONTROL 0x7A5 + + +#define ESP_CPU_CSR_PCER_U 0x800 +#define ESP_CPU_CSR_PCMR_U 0x801 +#define ESP_CPU_CSR_MCYCLE_U 0x802 + +#define ESP_CPU_CSR_GPIO_OEN 0x803 +#define ESP_CPU_CSR_GPIO_IN 0x804 +#define ESP_CPU_CSR_GPIO_OUT 0x805 + + +static RISCVException esp_cpu_csr_predicate(CPURISCVState *env, int csrno) { + return RISCV_EXCP_NONE; +} + + +static uint64_t esp_cpu_get_cycles(ESPCPUCycleCounter* cc) +{ + /* Let's simulate the cycle count between two reads of MCYCLE thanks to the time API. */ + /* Calculate the time elapsed between now and the previous call */ + uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + uint64_t diff = 0; + + /* If we are not in the first call, calculate the difference */ + if (cc->former_time != 0) { + /* Let's say that we have 1 instruction/clock cycle, so 1 instruction/6.25ns */ + assert(cc->divider != 0); + diff = (now - cc->former_time) / cc->divider; + } + cc->former_time = now; + cc->cycles += diff; + return cc->cycles; +} + + +/** + * Convert the given environment to the an ESP CPU. + * The environment is the field part of RISCVCPU, so retrieve the RISCVCPU address. + * In fact, RISCVCPU is overriden as EspRISCVCPU, we can then cast it safely. + */ +static EspRISCVCPU* esp_cpu_riscv_to_cpu(CPURISCVState *env) +{ + // RISCVCPU* riscv = (RISCVCPU*) ((void*) env - offsetof(RISCVCPU, env)); + RISCVCPU* riscv = container_of(env, RISCVCPU, env); + return ESP_CPU(riscv); +} + + +static RISCVException esp_cpu_csr_read(CPURISCVState *env, int csrno, target_ulong *ret_value) { + EspRISCVCPU *s = esp_cpu_riscv_to_cpu(env); + + if (csrno == ESP_CPU_CSR_MCYCLE_U) { + *ret_value = esp_cpu_get_cycles(&s->cc_user); + } else if (csrno == ESP_CPU_CSR_MCYCLE_M) { + *ret_value = esp_cpu_get_cycles(&s->cc_machine); + } else if (csrno >= ESP_CPU_CSR_TSELECT && csrno <= ESP_CPU_CSR_TCONTROL) { + /* Nothing special to do here */ + } else { + *ret_value = 0; + } + return RISCV_EXCP_NONE; +} + + +static RISCVException esp_cpu_csr_write(CPURISCVState *env, int csrno, target_ulong new_value) { + EspRISCVCPU *s = esp_cpu_riscv_to_cpu(env); + + if (csrno == ESP_CPU_CSR_MCYCLE_U) { + s->cc_user.cycles = new_value; + } else if (csrno == ESP_CPU_CSR_MCYCLE_M) { + s->cc_machine.cycles = new_value; + } else if (csrno >= ESP_CPU_CSR_TSELECT && csrno <= ESP_CPU_CSR_TCONTROL) { + /* Nothing special to do here */ + } + + return RISCV_EXCP_NONE; +} + + +riscv_csr_operations esp_cpu_csr_ops = { + .predicate = esp_cpu_csr_predicate, + .read = esp_cpu_csr_read, + .write = esp_cpu_csr_write +}; + + +/** + * Checks whether the CPU can accepts interrupts or not + */ +bool esp_cpu_accept_interrupts(EspRISCVCPU *cpu) +{ + /* Get the MIE bit out of the MSTATUS register */ + CPURISCVState *env = &cpu->parent_obj.env; + const bool mie = (riscv_csr_read(env, CSR_MSTATUS) & MSTATUS_MIE) != 0; + + return !cpu->irq_pending && mie; +} + + +/** + * Function called when an interrupt is incoming. + */ +static void esp_cpu_irq_handler(void *opaque, int n, int level) +{ + EspRISCVCPU *cpu = (EspRISCVCPU*) opaque; + + /* Interrupt incoming if level is not 0, make sure we can receive interrupts */ + if (level && esp_cpu_accept_interrupts(cpu)) { + cpu->irq_pending = true; + cpu->irq_cause = n; + qemu_irq_raise(cpu->parent_irq); + } +} + + +/** + * TCG operation called when the CPU has to actually jump to the interrupt handler. + */ +static bool esp_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + /* We could re-implement the whole interrupt process from here. + * The simplest solution however is to call the parent's implementation and + * replace the most important part for us: the mcause. */ + EspRISCVCPU *cpu = ESP_CPU(cs); + EspRISCVCPUClass *klass = ESP_CPU_GET_CLASS(cpu); + + const bool accepted = klass->parent_exec_interrupt(cs, interrupt_request); + + if (accepted) { + CPURISCVState *env = &cpu->parent_obj.env; + const bool vectored = (env->mtvec & 3) == 1; + const uint32_t cause = cpu->irq_cause; + + /* IRQ has been acknowledged by the parent CPU, it is not pending anymore */ + cpu->irq_pending = false; + qemu_irq_lower(cpu->parent_irq); + + /* Update the mcause and the relevant PC */ + env->mcause = RISCV_EXCP_INT_FLAG | cause; + + /* Recalculate the PC thanks to the cause */ + env->pc = (env->mtvec >> 2 << 2) + (vectored ? cause * 4 : 0); + } + + return accepted; +} + + +/** + * Taken from `cpu.c`, as this function is private in that file + */ +static void set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext) +{ + env->misa_mxl_max = env->misa_mxl = mxl; + env->misa_ext_mask = env->misa_ext = ext; +} + +static void esp_cpu_reset(void *opaque) +{ + EspRISCVCPU *cpu = opaque; + cpu->irq_pending = 0; + qemu_irq_lower(cpu->parent_irq); + cpu_reset(CPU(cpu)); +} + +static void esp_cpu_realize(DeviceState *dev, Error **errp) +{ + EspRISCVCPU *espcpu = ESP_CPU(dev); + EspRISCVCPUClass *klass = ESP_CPU_GET_CLASS(dev); + + espcpu->parent_obj.env.mhartid = espcpu->hartid_base; + qemu_register_reset(esp_cpu_reset, espcpu); + + klass->parent_realize(dev, errp); + + if (riscv_cpu_claim_interrupts(&espcpu->parent_obj, MIP_MEIP) < 0) { + error_report("MIP_MEIP already claimed"); + exit(1); + } +} + +static void esp_cpu_init(Object *obj) +{ + EspRISCVCPU *s = ESP_CPU(obj); + RISCVCPU *cpu = RISCV_CPU(obj); + CPURISCVState *env = &cpu->env; + set_misa(env, MXL_RV32, RVI | RVM | RVC); + + /* Since 8.0, it is also required to set CPU's cfg extension booleans, unfortunately, there is no + * public function to do this, so we have to manually write to the fields. */ + cpu->cfg.ext_i = true; + cpu->cfg.ext_m = true; + cpu->cfg.ext_c = true; + + /* Initialize the IRQ lines */ + qdev_init_gpio_in_named_with_opaque(DEVICE(s), + esp_cpu_irq_handler, s, + ESP_CPU_IRQ_LINES_NAME, ESP_CPU_INT_LINES + 1); + + /* Initialize the parent IRQ line that will be used to notify the parent class when an interrupt + * request is incoming. */ + s->parent_irq = qdev_get_gpio_in(DEVICE(s), IRQ_M_EXT); + + /* Set the user operations */ + riscv_set_csr_ops(CSR_USTATUS, &esp_cpu_csr_ops); + + /* Override debug CSRs as they are not all supported by QEMU's RISC-V core */ + for (int i = ESP_CPU_CSR_TSELECT; i <= ESP_CPU_CSR_TCONTROL; i++) { + riscv_set_csr_ops(i, &esp_cpu_csr_ops); + } + + /* Register all non-standard Control and Status registers */ + riscv_set_csr_ops(ESP_CPU_CSR_PCER_M, &esp_cpu_csr_ops); + riscv_set_csr_ops(ESP_CPU_CSR_PCMR_M, &esp_cpu_csr_ops); + riscv_set_csr_ops(ESP_CPU_CSR_MCYCLE_M, &esp_cpu_csr_ops); + + riscv_set_csr_ops(ESP_CPU_CSR_PCER_U, &esp_cpu_csr_ops); + riscv_set_csr_ops(ESP_CPU_CSR_PCMR_U, &esp_cpu_csr_ops); + riscv_set_csr_ops(ESP_CPU_CSR_MCYCLE_U, &esp_cpu_csr_ops); + + /* Re-use the macro that checks and casts any generic/parent class to the real child instance */ + s->cc_machine = (ESPCPUCycleCounter) { + .divider = 6, /* 6.25ns per instruction at 160MHz. */ + }; + s->cc_user = (ESPCPUCycleCounter) { + .divider = 6, /* Should be using the target configured CPU clock frequency instead. */ + }; +} + +static Property riscv_harts_props[] = { + DEFINE_PROP_UINT32("hartid-base", EspRISCVCPU, hartid_base, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static struct TCGCPUOps tcg_ops = { 0 }; + +static void esp_cpu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + CPUClass *cc = CPU_CLASS(klass); + EspRISCVCPUClass *cpuclass = ESP_CPU_CLASS(klass); + + device_class_set_props(dc, riscv_harts_props); + /* Save the parent realize function in order to be able to call it later */ + device_class_set_parent_realize(dc, esp_cpu_realize, + &cpuclass->parent_realize); + // device_class_set_parent_reset(dc, esp_cpu_reset, &cpuclass->parent_reset); + + /* The goal of this RISC-V CPU child class is to override the way interrupts are handled. + * In theory, it would be enough to override `do_interrupt` function from the CPU's TCGCPUOps + * structure, however, in practice, we have to override `riscv_cpu_exec_interrupt` function. + * This is due to the fact that the RISC-V implementation doesn't call the `do_interrupt` routine + * from its TCGCPUOps routine, but directly calls its `riscv_cpu_do_interrupt` function. + * As that structure may be constant, we have to copy it in order to replace one of its field. */ + memcpy(&tcg_ops, cc->tcg_ops, sizeof(struct TCGCPUOps)); + + /* Copy the parent's exec_interrupt function as we will execute it later */ + cpuclass->parent_exec_interrupt = tcg_ops.cpu_exec_interrupt; + + /* Replace it with our overriden implementation */ + tcg_ops.cpu_exec_interrupt = esp_cpu_exec_interrupt; + cc->tcg_ops = &tcg_ops; +} + +static const TypeInfo esp_cpu_info = { + .name = TYPE_ESP_RISCV_CPU, + .parent = TYPE_RISCV_CPU_BASE32, + .instance_size = sizeof(EspRISCVCPU), + .instance_align = __alignof__(EspRISCVCPU), + .instance_init = esp_cpu_init, + .class_size = sizeof(EspRISCVCPUClass), + .class_init = esp_cpu_class_init, +}; + +static void esp_cpu_register_type(void) +{ + type_register_static(&esp_cpu_info); +} + +type_init(esp_cpu_register_type) diff --git a/target/riscv/esp_cpu.h b/target/riscv/esp_cpu.h new file mode 100644 index 000000000000..9923e2539d90 --- /dev/null +++ b/target/riscv/esp_cpu.h @@ -0,0 +1,86 @@ +/* + * Espressif RISC-V CPU + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#pragma once + +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/registerfields.h" +#include "cpu.h" + +/* Make sure we are not in CONFIG_USER_ONLY */ +#if defined(CONFIG_USER_ONLY) || !defined(CONFIG_SOFTMMU) +#error "ESP RISC-V Core only works in system emulation and in SOFTMMU configuration" +#endif + +#include "hw/core/tcg-cpu-ops.h" + +#define ESP_CPU_IRQ_LINES_NAME "espressif-cpu-irq-lines" + +#define TYPE_ESP_RISCV_CPU "espressif-riscv-cpu" +#define ESP_CPU(obj) OBJECT_CHECK(EspRISCVCPU, (obj), TYPE_ESP_RISCV_CPU) +#define ESP_CPU_GET_CLASS(obj) OBJECT_GET_CLASS(EspRISCVCPUClass, obj, TYPE_ESP_RISCV_CPU) +#define ESP_CPU_CLASS(klass) OBJECT_CLASS_CHECK(EspRISCVCPUClass, klass, TYPE_ESP_RISCV_CPU) + +#define ESP_CPU_INT_LINES 31 + + +/* Define a type that will be used to generate a cycle counter */ +typedef struct { + uint64_t former_time; + uint64_t cycles; + /* The number of nanosecond an instruction takes to execute */ + uint64_t divider; +} ESPCPUCycleCounter; + + +/** + * Espressif's RISC-V core is different from standard RISC-V because of the way interrupts are handled. + * Extend the standard RISC-V core implementation. + */ +typedef struct EspRISCVCPU { + /*< private >*/ + RISCVCPU parent_obj; + + /* Cycle counts */ + ESPCPUCycleCounter cc_user; + ESPCPUCycleCounter cc_machine; + + /*< public >*/ + /* The parent object already has a reset vector property */ + uint32_t hartid_base; + /* Parent IRQ_M line */ + qemu_irq parent_irq; + /* Number of the IRQ that triggered the interrupt */ + uint32_t irq_cause; + /* Interrupts are not always synchronous, so MIE may still be set to 1 while an + * interrupt is waiting to be handled. So, keep a mirrored MIE to mark whether + * we can receive interrupts or not. */ + bool irq_pending; +} EspRISCVCPU; + + +typedef struct EspRISCVCPUClass { + /*< private >*/ + RISCVCPUClass parent_class; + + /*< public >*/ + DeviceRealize parent_realize; + DeviceReset parent_reset; + bool (*parent_exec_interrupt)(CPUState *cpu, int interrupt_request); +} EspRISCVCPUClass; + +/** + * @brief Check whether the current CPU state can accept interrupts or not. + * If an interrupt is currently pending and the MEPC was not set to the reset vector yet, + * this function returns false. + * If MIE bit is not set in the MSTATUS register, it will also return false. + */ +bool esp_cpu_accept_interrupts(EspRISCVCPU *cpu); diff --git a/target/riscv/meson.build b/target/riscv/meson.build index 5dee37a242fb..0d46014e3357 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -22,6 +22,7 @@ riscv_ss.add(files( 'crypto_helper.c' )) riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c')) +riscv_ss.add(when: 'CONFIG_RISCV_ESP32C3', if_true: files('esp_cpu.c')) riscv_softmmu_ss = ss.source_set() riscv_softmmu_ss.add(files( diff --git a/target/xtensa/core-esp32.c b/target/xtensa/core-esp32.c new file mode 100644 index 000000000000..5a208b210219 --- /dev/null +++ b/target/xtensa/core-esp32.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/gdbstub.h" +#include "qemu/host-utils.h" + +#include "core-esp32/core-isa.h" +#include "overlay_tool.h" + +#define xtensa_modules xtensa_modules_esp32 +#include "core-esp32/xtensa-modules.inc.c" + +static const XtensaOpcodeTranslators* esp32_opcode_translators[] = { + &xtensa_core_opcodes, + &xtensa_fpu_opcodes, + NULL +}; + +static XtensaConfig xtensa_core_esp32 __attribute__((unused)) = { + .name = "esp32", + .gdb_regmap = { + .reg = { +#include "core-esp32/gdb-config.inc.c" + } + }, + .isa_internal = &xtensa_modules, + .clock_freq_khz = 40000, + .opcode_translators = esp32_opcode_translators, + DEFAULT_SECTIONS +}; + +REGISTER_CORE(xtensa_core_esp32) diff --git a/target/xtensa/core-esp32/core-isa.h b/target/xtensa/core-esp32/core-isa.h new file mode 100644 index 000000000000..f3f4e45f001f --- /dev/null +++ b/target/xtensa/core-esp32/core-isa.h @@ -0,0 +1,655 @@ +/* + * xtensa/config/core-isa.h -- HAL definitions that are dependent on Xtensa + * processor CORE configuration + * + * See , which includes this file, for more details. + */ + +/* Xtensa processor core configuration information. + + Copyright (c) 1999-2016 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _XTENSA_CORE_CONFIGURATION_H +#define _XTENSA_CORE_CONFIGURATION_H + + +/**************************************************************************** + Parameters Useful for Any Code, USER or PRIVILEGED + ****************************************************************************/ + +/* + * Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is + * configured, and a value of 0 otherwise. These macros are always defined. + */ + + +/*---------------------------------------------------------------------- + ISA + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_BE 0 /* big-endian byte ordering */ +#define XCHAL_HAVE_WINDOWED 1 /* windowed registers option */ +#define XCHAL_NUM_AREGS 64 /* num of physical addr regs */ +#define XCHAL_NUM_AREGS_LOG2 6 /* log2(XCHAL_NUM_AREGS) */ +#define XCHAL_MAX_INSTRUCTION_SIZE 3 /* max instr bytes (3..8) */ +#define XCHAL_HAVE_DEBUG 1 /* debug option */ +#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */ +#define XCHAL_HAVE_LOOPS 1 /* zero-overhead loops */ +#define XCHAL_LOOP_BUFFER_SIZE 256 /* zero-ov. loop instr buffer size */ +#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */ +#define XCHAL_HAVE_MINMAX 1 /* MIN/MAX instructions */ +#define XCHAL_HAVE_SEXT 1 /* SEXT instruction */ +#define XCHAL_HAVE_DEPBITS 0 /* DEPBITS instruction */ +#define XCHAL_HAVE_CLAMPS 1 /* CLAMPS instruction */ +#define XCHAL_HAVE_MUL16 1 /* MUL16S/MUL16U instructions */ +#define XCHAL_HAVE_MUL32 1 /* MULL instruction */ +#define XCHAL_HAVE_MUL32_HIGH 1 /* MULUH/MULSH instructions */ +#define XCHAL_HAVE_DIV32 1 /* QUOS/QUOU/REMS/REMU instructions */ +#define XCHAL_HAVE_L32R 1 /* L32R instruction */ +#define XCHAL_HAVE_ABSOLUTE_LITERALS 0 /* non-PC-rel (extended) L32R */ +#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */ +#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */ +#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */ +#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */ +#define XCHAL_HAVE_CALL4AND12 1 /* (obsolete option) */ +#define XCHAL_HAVE_ABS 1 /* ABS instruction */ +/*#define XCHAL_HAVE_POPC 0*/ /* POPC instruction */ +/*#define XCHAL_HAVE_CRC 0*/ /* CRC instruction */ +#define XCHAL_HAVE_RELEASE_SYNC 1 /* L32AI/S32RI instructions */ +#define XCHAL_HAVE_S32C1I 1 /* S32C1I instruction */ +#define XCHAL_HAVE_SPECULATION 0 /* speculation */ +#define XCHAL_HAVE_FULL_RESET 1 /* all regs/state reset */ +#define XCHAL_NUM_CONTEXTS 1 /* */ +#define XCHAL_NUM_MISC_REGS 4 /* num of scratch regs (0..4) */ +#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */ +#define XCHAL_HAVE_PRID 1 /* processor ID register */ +#define XCHAL_HAVE_EXTERN_REGS 1 /* WER/RER instructions */ +#define XCHAL_HAVE_MX 0 /* MX core (Tensilica internal) */ +#define XCHAL_HAVE_MP_INTERRUPTS 0 /* interrupt distributor port */ +#define XCHAL_HAVE_MP_RUNSTALL 0 /* core RunStall control port */ +#define XCHAL_HAVE_PSO 0 /* Power Shut-Off */ +#define XCHAL_HAVE_PSO_CDM 0 /* core/debug/mem pwr domains */ +#define XCHAL_HAVE_PSO_FULL_RETENTION 0 /* all regs preserved on PSO */ +#define XCHAL_HAVE_THREADPTR 1 /* THREADPTR register */ +#define XCHAL_HAVE_BOOLEANS 1 /* boolean registers */ +#define XCHAL_HAVE_CP 1 /* CPENABLE reg (coprocessor) */ +#define XCHAL_CP_MAXCFG 8 /* max allowed cp id plus one */ +#define XCHAL_HAVE_MAC16 1 /* MAC16 package */ + +#define XCHAL_HAVE_FUSION 0 /* Fusion*/ +#define XCHAL_HAVE_FUSION_FP 0 /* Fusion FP option */ +#define XCHAL_HAVE_FUSION_LOW_POWER 0 /* Fusion Low Power option */ +#define XCHAL_HAVE_FUSION_AES 0 /* Fusion BLE/Wifi AES-128 CCM option */ +#define XCHAL_HAVE_FUSION_CONVENC 0 /* Fusion Conv Encode option */ +#define XCHAL_HAVE_FUSION_LFSR_CRC 0 /* Fusion LFSR-CRC option */ +#define XCHAL_HAVE_FUSION_BITOPS 0 /* Fusion Bit Operations Support option */ +#define XCHAL_HAVE_FUSION_AVS 0 /* Fusion AVS option */ +#define XCHAL_HAVE_FUSION_16BIT_BASEBAND 0 /* Fusion 16-bit Baseband option */ +#define XCHAL_HAVE_FUSION_VITERBI 0 /* Fusion Viterbi option */ +#define XCHAL_HAVE_FUSION_SOFTDEMAP 0 /* Fusion Soft Bit Demap option */ +#define XCHAL_HAVE_HIFIPRO 0 /* HiFiPro Audio Engine pkg */ +#define XCHAL_HAVE_HIFI4 0 /* HiFi4 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI4_VFPU 0 /* HiFi4 Audio Engine VFPU option */ +#define XCHAL_HAVE_HIFI3 0 /* HiFi3 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI3_VFPU 0 /* HiFi3 Audio Engine VFPU option */ +#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI2EP 0 /* HiFi2EP */ +#define XCHAL_HAVE_HIFI_MINI 0 + + +#define XCHAL_HAVE_VECTORFPU2005 0 /* vector or user floating-point pkg */ +#define XCHAL_HAVE_USER_DPFPU 0 /* user DP floating-point pkg */ +#define XCHAL_HAVE_USER_SPFPU 0 /* user DP floating-point pkg */ +#define XCHAL_HAVE_FP 1 /* single prec floating point */ +#define XCHAL_HAVE_FP_DIV 1 /* FP with DIV instructions */ +#define XCHAL_HAVE_FP_RECIP 1 /* FP with RECIP instructions */ +#define XCHAL_HAVE_FP_SQRT 1 /* FP with SQRT instructions */ +#define XCHAL_HAVE_FP_RSQRT 1 /* FP with RSQRT instructions */ +#define XCHAL_HAVE_DFP 0 /* double precision FP pkg */ +#define XCHAL_HAVE_DFP_DIV 0 /* DFP with DIV instructions */ +#define XCHAL_HAVE_DFP_RECIP 0 /* DFP with RECIP instructions*/ +#define XCHAL_HAVE_DFP_SQRT 0 /* DFP with SQRT instructions */ +#define XCHAL_HAVE_DFP_RSQRT 0 /* DFP with RSQRT instructions*/ +#define XCHAL_HAVE_DFP_ACCEL 1 /* double precision FP acceleration pkg */ +#define XCHAL_HAVE_DFP_accel XCHAL_HAVE_DFP_ACCEL /* for backward compatibility */ + +#define XCHAL_HAVE_DFPU_SINGLE_ONLY 1 /* DFPU Coprocessor, single precision only */ +#define XCHAL_HAVE_DFPU_SINGLE_DOUBLE 0 /* DFPU Coprocessor, single and double precision */ +#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */ +#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */ +#define XCHAL_HAVE_PDX4 0 /* PDX4 */ +#define XCHAL_HAVE_CONNXD2 0 /* ConnX D2 pkg */ +#define XCHAL_HAVE_CONNXD2_DUALLSFLIX 0 /* ConnX D2 & Dual LoadStore Flix */ +#define XCHAL_HAVE_BBE16 0 /* ConnX BBE16 pkg */ +#define XCHAL_HAVE_BBE16_RSQRT 0 /* BBE16 & vector recip sqrt */ +#define XCHAL_HAVE_BBE16_VECDIV 0 /* BBE16 & vector divide */ +#define XCHAL_HAVE_BBE16_DESPREAD 0 /* BBE16 & despread */ +#define XCHAL_HAVE_BBENEP 0 /* ConnX BBENEP pkgs */ +#define XCHAL_HAVE_BSP3 0 /* ConnX BSP3 pkg */ +#define XCHAL_HAVE_BSP3_TRANSPOSE 0 /* BSP3 & transpose32x32 */ +#define XCHAL_HAVE_SSP16 0 /* ConnX SSP16 pkg */ +#define XCHAL_HAVE_SSP16_VITERBI 0 /* SSP16 & viterbi */ +#define XCHAL_HAVE_TURBO16 0 /* ConnX Turbo16 pkg */ +#define XCHAL_HAVE_BBP16 0 /* ConnX BBP16 pkg */ +#define XCHAL_HAVE_FLIX3 0 /* basic 3-way FLIX option */ +#define XCHAL_HAVE_GRIVPEP 0 /* GRIVPEP is General Release of IVPEP */ +#define XCHAL_HAVE_GRIVPEP_HISTOGRAM 0 /* Histogram option on GRIVPEP */ + + +/*---------------------------------------------------------------------- + MISC + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_LOADSTORE_UNITS 1 /* load/store units */ +#define XCHAL_NUM_WRITEBUFFER_ENTRIES 4 /* size of write buffer */ +#define XCHAL_INST_FETCH_WIDTH 4 /* instr-fetch width in bytes */ +#define XCHAL_DATA_WIDTH 4 /* data width in bytes */ +#define XCHAL_DATA_PIPE_DELAY 2 /* d-side pipeline delay + (1 = 5-stage, 2 = 7-stage) */ +#define XCHAL_CLOCK_GATING_GLOBAL 1 /* global clock gating */ +#define XCHAL_CLOCK_GATING_FUNCUNIT 1 /* funct. unit clock gating */ +/* In T1050, applies to selected core load and store instructions (see ISA): */ +#define XCHAL_UNALIGNED_LOAD_EXCEPTION 0 /* unaligned loads cause exc. */ +#define XCHAL_UNALIGNED_STORE_EXCEPTION 0 /* unaligned stores cause exc.*/ +#define XCHAL_UNALIGNED_LOAD_HW 1 /* unaligned loads work in hw */ +#define XCHAL_UNALIGNED_STORE_HW 1 /* unaligned stores work in hw*/ + +#define XCHAL_SW_VERSION 1100003 /* sw version of this header */ + +#define XCHAL_CORE_ID "esp32_v3_49_prod" /* alphanum core name + (CoreID) set in the Xtensa + Processor Generator */ + +#define XCHAL_BUILD_UNIQUE_ID 0x0005FE96 /* 22-bit sw build ID */ + +/* + * These definitions describe the hardware targeted by this software. + */ +#define XCHAL_HW_CONFIGID0 0xC2BCFFFE /* ConfigID hi 32 bits*/ +#define XCHAL_HW_CONFIGID1 0x1CC5FE96 /* ConfigID lo 32 bits*/ +#define XCHAL_HW_VERSION_NAME "LX6.0.3" /* full version name */ +#define XCHAL_HW_VERSION_MAJOR 2600 /* major ver# of targeted hw */ +#define XCHAL_HW_VERSION_MINOR 3 /* minor ver# of targeted hw */ +#define XCHAL_HW_VERSION 260003 /* major*100+minor */ +#define XCHAL_HW_REL_LX6 1 +#define XCHAL_HW_REL_LX6_0 1 +#define XCHAL_HW_REL_LX6_0_3 1 +#define XCHAL_HW_CONFIGID_RELIABLE 1 +/* If software targets a *range* of hardware versions, these are the bounds: */ +#define XCHAL_HW_MIN_VERSION_MAJOR 2600 /* major v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MINOR 3 /* minor v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION 260003 /* earliest targeted hw */ +#define XCHAL_HW_MAX_VERSION_MAJOR 2600 /* major v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MINOR 3 /* minor v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION 260003 /* latest targeted hw */ + + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_ICACHE_LINESIZE 4 /* I-cache line size in bytes */ +#define XCHAL_DCACHE_LINESIZE 4 /* D-cache line size in bytes */ +#define XCHAL_ICACHE_LINEWIDTH 2 /* log2(I line size in bytes) */ +#define XCHAL_DCACHE_LINEWIDTH 2 /* log2(D line size in bytes) */ + +#define XCHAL_ICACHE_SIZE 0 /* I-cache size in bytes or 0 */ +#define XCHAL_DCACHE_SIZE 0 /* D-cache size in bytes or 0 */ + +#define XCHAL_DCACHE_IS_WRITEBACK 0 /* writeback feature */ +#define XCHAL_DCACHE_IS_COHERENT 0 /* MP coherence feature */ + +#define XCHAL_HAVE_PREFETCH 0 /* PREFCTL register */ +#define XCHAL_HAVE_PREFETCH_L1 0 /* prefetch to L1 dcache */ +#define XCHAL_PREFETCH_CASTOUT_LINES 0 /* dcache pref. castout bufsz */ +#define XCHAL_PREFETCH_ENTRIES 0 /* cache prefetch entries */ +#define XCHAL_PREFETCH_BLOCK_ENTRIES 0 /* prefetch block streams */ +#define XCHAL_HAVE_CACHE_BLOCKOPS 0 /* block prefetch for caches */ +#define XCHAL_HAVE_ICACHE_TEST 0 /* Icache test instructions */ +#define XCHAL_HAVE_DCACHE_TEST 0 /* Dcache test instructions */ +#define XCHAL_HAVE_ICACHE_DYN_WAYS 0 /* Icache dynamic way support */ +#define XCHAL_HAVE_DCACHE_DYN_WAYS 0 /* Dcache dynamic way support */ + + + + +/**************************************************************************** + Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code + ****************************************************************************/ + + +#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY + +/*---------------------------------------------------------------------- + CACHE + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_PIF 1 /* any outbound PIF present */ +#define XCHAL_HAVE_AXI 0 /* AXI bus */ + +#define XCHAL_HAVE_PIF_WR_RESP 0 /* pif write response */ +#define XCHAL_HAVE_PIF_REQ_ATTR 0 /* pif attribute */ + +/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */ + +/* Number of cache sets in log2(lines per way): */ +#define XCHAL_ICACHE_SETWIDTH 0 +#define XCHAL_DCACHE_SETWIDTH 0 + +/* Cache set associativity (number of ways): */ +#define XCHAL_ICACHE_WAYS 1 +#define XCHAL_DCACHE_WAYS 1 + +/* Cache features: */ +#define XCHAL_ICACHE_LINE_LOCKABLE 0 +#define XCHAL_DCACHE_LINE_LOCKABLE 0 +#define XCHAL_ICACHE_ECC_PARITY 0 +#define XCHAL_DCACHE_ECC_PARITY 0 + +/* Cache access size in bytes (affects operation of SICW instruction): */ +#define XCHAL_ICACHE_ACCESS_SIZE 1 +#define XCHAL_DCACHE_ACCESS_SIZE 1 + +#define XCHAL_DCACHE_BANKS 0 /* number of banks */ + +/* Number of encoded cache attr bits (see for decoded bits): */ +#define XCHAL_CA_BITS 4 + + +/*---------------------------------------------------------------------- + INTERNAL I/D RAM/ROMs and XLMI + ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_INSTROM 1 /* number of core instr. ROMs */ +#define XCHAL_NUM_INSTRAM 2 /* number of core instr. RAMs */ +#define XCHAL_NUM_DATAROM 1 /* number of core data ROMs */ +#define XCHAL_NUM_DATARAM 2 /* number of core data RAMs */ +#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/ +#define XCHAL_NUM_XLMI 1 /* number of core XLMI ports */ + +/* Instruction ROM 0: */ +#define XCHAL_INSTROM0_VADDR 0x40800000 /* virtual address */ +#define XCHAL_INSTROM0_PADDR 0x40800000 /* physical address */ +#define XCHAL_INSTROM0_SIZE 4194304 /* size in bytes */ +#define XCHAL_INSTROM0_ECC_PARITY 0 /* ECC/parity type, 0=none */ + +/* Instruction RAM 0: */ +#define XCHAL_INSTRAM0_VADDR 0x40000000 /* virtual address */ +#define XCHAL_INSTRAM0_PADDR 0x40000000 /* physical address */ +#define XCHAL_INSTRAM0_SIZE 4194304 /* size in bytes */ +#define XCHAL_INSTRAM0_ECC_PARITY 0 /* ECC/parity type, 0=none */ + +/* Instruction RAM 1: */ +#define XCHAL_INSTRAM1_VADDR 0x40400000 /* virtual address */ +#define XCHAL_INSTRAM1_PADDR 0x40400000 /* physical address */ +#define XCHAL_INSTRAM1_SIZE 4194304 /* size in bytes */ +#define XCHAL_INSTRAM1_ECC_PARITY 0 /* ECC/parity type, 0=none */ + +/* Data ROM 0: */ +#define XCHAL_DATAROM0_VADDR 0x3F400000 /* virtual address */ +#define XCHAL_DATAROM0_PADDR 0x3F400000 /* physical address */ +#define XCHAL_DATAROM0_SIZE 4194304 /* size in bytes */ +#define XCHAL_DATAROM0_ECC_PARITY 0 /* ECC/parity type, 0=none */ +#define XCHAL_DATAROM0_BANKS 1 /* number of banks */ + +/* Data RAM 0: */ +#define XCHAL_DATARAM0_VADDR 0x3FF80000 /* virtual address */ +#define XCHAL_DATARAM0_PADDR 0x3FF80000 /* physical address */ +#define XCHAL_DATARAM0_SIZE 524288 /* size in bytes */ +#define XCHAL_DATARAM0_ECC_PARITY 0 /* ECC/parity type, 0=none */ +#define XCHAL_DATARAM0_BANKS 1 /* number of banks */ + +/* Data RAM 1: */ +#define XCHAL_DATARAM1_VADDR 0x3F800000 /* virtual address */ +#define XCHAL_DATARAM1_PADDR 0x3F800000 /* physical address */ +#define XCHAL_DATARAM1_SIZE 4194304 /* size in bytes */ +#define XCHAL_DATARAM1_ECC_PARITY 0 /* ECC/parity type, 0=none */ +#define XCHAL_DATARAM1_BANKS 1 /* number of banks */ + +/* XLMI Port 0: */ +#define XCHAL_XLMI0_VADDR 0x3FF00000 /* virtual address */ +#define XCHAL_XLMI0_PADDR 0x3FF00000 /* physical address */ +#define XCHAL_XLMI0_SIZE 524288 /* size in bytes */ +#define XCHAL_XLMI0_ECC_PARITY 0 /* ECC/parity type, 0=none */ + +#define XCHAL_HAVE_IMEM_LOADSTORE 1 /* can load/store to IROM/IRAM*/ + + +/*---------------------------------------------------------------------- + INTERRUPTS and TIMERS + ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */ +#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */ +#define XCHAL_HAVE_NMI 1 /* non-maskable interrupt */ +#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */ +#define XCHAL_NUM_TIMERS 3 /* number of CCOMPAREn regs */ +#define XCHAL_NUM_INTERRUPTS 32 /* number of interrupts */ +#define XCHAL_NUM_INTERRUPTS_LOG2 5 /* ceil(log2(NUM_INTERRUPTS)) */ +#define XCHAL_NUM_EXTINTERRUPTS 26 /* num of external interrupts */ +#define XCHAL_NUM_INTLEVELS 6 /* number of interrupt levels + (not including level zero) */ +#define XCHAL_EXCM_LEVEL 3 /* level masked by PS.EXCM */ + /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */ + +/* Masks of interrupts at each interrupt level: */ +#define XCHAL_INTLEVEL1_MASK 0x000637FF +#define XCHAL_INTLEVEL2_MASK 0x00380000 +#define XCHAL_INTLEVEL3_MASK 0x28C08800 +#define XCHAL_INTLEVEL4_MASK 0x53000000 +#define XCHAL_INTLEVEL5_MASK 0x84010000 +#define XCHAL_INTLEVEL6_MASK 0x00000000 +#define XCHAL_INTLEVEL7_MASK 0x00004000 + +/* Masks of interrupts at each range 1..n of interrupt levels: */ +#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x000637FF +#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x003E37FF +#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x28FEBFFF +#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x7BFEBFFF +#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0xFFFFBFFF +#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0xFFFFBFFF +#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0xFFFFFFFF + +/* Level of each interrupt: */ +#define XCHAL_INT0_LEVEL 1 +#define XCHAL_INT1_LEVEL 1 +#define XCHAL_INT2_LEVEL 1 +#define XCHAL_INT3_LEVEL 1 +#define XCHAL_INT4_LEVEL 1 +#define XCHAL_INT5_LEVEL 1 +#define XCHAL_INT6_LEVEL 1 +#define XCHAL_INT7_LEVEL 1 +#define XCHAL_INT8_LEVEL 1 +#define XCHAL_INT9_LEVEL 1 +#define XCHAL_INT10_LEVEL 1 +#define XCHAL_INT11_LEVEL 3 +#define XCHAL_INT12_LEVEL 1 +#define XCHAL_INT13_LEVEL 1 +#define XCHAL_INT14_LEVEL 7 +#define XCHAL_INT15_LEVEL 3 +#define XCHAL_INT16_LEVEL 5 +#define XCHAL_INT17_LEVEL 1 +#define XCHAL_INT18_LEVEL 1 +#define XCHAL_INT19_LEVEL 2 +#define XCHAL_INT20_LEVEL 2 +#define XCHAL_INT21_LEVEL 2 +#define XCHAL_INT22_LEVEL 3 +#define XCHAL_INT23_LEVEL 3 +#define XCHAL_INT24_LEVEL 4 +#define XCHAL_INT25_LEVEL 4 +#define XCHAL_INT26_LEVEL 5 +#define XCHAL_INT27_LEVEL 3 +#define XCHAL_INT28_LEVEL 4 +#define XCHAL_INT29_LEVEL 3 +#define XCHAL_INT30_LEVEL 4 +#define XCHAL_INT31_LEVEL 5 +#define XCHAL_DEBUGLEVEL 6 /* debug interrupt level */ +#define XCHAL_HAVE_DEBUG_EXTERN_INT 1 /* OCD external db interrupt */ +#define XCHAL_NMILEVEL 7 /* NMI "level" (for use with + EXCSAVE/EPS/EPC_n, RFI n) */ + +/* Type of each interrupt: */ +#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT6_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT7_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT10_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT11_TYPE XTHAL_INTTYPE_PROFILING +#define XCHAL_INT12_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT13_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT14_TYPE XTHAL_INTTYPE_NMI +#define XCHAL_INT15_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT16_TYPE XTHAL_INTTYPE_TIMER +#define XCHAL_INT17_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT18_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT19_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT20_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT21_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT22_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT23_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT24_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT25_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT26_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT27_TYPE XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT28_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT29_TYPE XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT30_TYPE XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT31_TYPE XTHAL_INTTYPE_EXTERN_LEVEL + +/* Masks of interrupts for each type of interrupt: */ +#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0x00000000 +#define XCHAL_INTTYPE_MASK_SOFTWARE 0x20000080 +#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x50400400 +#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x8FBE333F +#define XCHAL_INTTYPE_MASK_TIMER 0x00018040 +#define XCHAL_INTTYPE_MASK_NMI 0x00004000 +#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000000 +#define XCHAL_INTTYPE_MASK_PROFILING 0x00000800 + +/* Interrupt numbers assigned to specific interrupt sources: */ +#define XCHAL_TIMER0_INTERRUPT 6 /* CCOMPARE0 */ +#define XCHAL_TIMER1_INTERRUPT 15 /* CCOMPARE1 */ +#define XCHAL_TIMER2_INTERRUPT 16 /* CCOMPARE2 */ +#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED +#define XCHAL_NMI_INTERRUPT 14 /* non-maskable interrupt */ +#define XCHAL_PROFILING_INTERRUPT 11 /* profiling interrupt */ + +/* Interrupt numbers for levels at which only one interrupt is configured: */ +#define XCHAL_INTLEVEL7_NUM 14 +/* (There are many interrupts each at level(s) 1, 2, 3, 4, 5.) */ + + +/* + * External interrupt mapping. + * These macros describe how Xtensa processor interrupt numbers + * (as numbered internally, eg. in INTERRUPT and INTENABLE registers) + * map to external BInterrupt pins, for those interrupts + * configured as external (level-triggered, edge-triggered, or NMI). + * See the Xtensa processor databook for more details. + */ + +/* Core interrupt numbers mapped to each EXTERNAL BInterrupt pin number: */ +#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */ +#define XCHAL_EXTINT1_NUM 1 /* (intlevel 1) */ +#define XCHAL_EXTINT2_NUM 2 /* (intlevel 1) */ +#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */ +#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */ +#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */ +#define XCHAL_EXTINT6_NUM 8 /* (intlevel 1) */ +#define XCHAL_EXTINT7_NUM 9 /* (intlevel 1) */ +#define XCHAL_EXTINT8_NUM 10 /* (intlevel 1) */ +#define XCHAL_EXTINT9_NUM 12 /* (intlevel 1) */ +#define XCHAL_EXTINT10_NUM 13 /* (intlevel 1) */ +#define XCHAL_EXTINT11_NUM 14 /* (intlevel 7) */ +#define XCHAL_EXTINT12_NUM 17 /* (intlevel 1) */ +#define XCHAL_EXTINT13_NUM 18 /* (intlevel 1) */ +#define XCHAL_EXTINT14_NUM 19 /* (intlevel 2) */ +#define XCHAL_EXTINT15_NUM 20 /* (intlevel 2) */ +#define XCHAL_EXTINT16_NUM 21 /* (intlevel 2) */ +#define XCHAL_EXTINT17_NUM 22 /* (intlevel 3) */ +#define XCHAL_EXTINT18_NUM 23 /* (intlevel 3) */ +#define XCHAL_EXTINT19_NUM 24 /* (intlevel 4) */ +#define XCHAL_EXTINT20_NUM 25 /* (intlevel 4) */ +#define XCHAL_EXTINT21_NUM 26 /* (intlevel 5) */ +#define XCHAL_EXTINT22_NUM 27 /* (intlevel 3) */ +#define XCHAL_EXTINT23_NUM 28 /* (intlevel 4) */ +#define XCHAL_EXTINT24_NUM 30 /* (intlevel 4) */ +#define XCHAL_EXTINT25_NUM 31 /* (intlevel 5) */ +/* EXTERNAL BInterrupt pin numbers mapped to each core interrupt number: */ +#define XCHAL_INT0_EXTNUM 0 /* (intlevel 1) */ +#define XCHAL_INT1_EXTNUM 1 /* (intlevel 1) */ +#define XCHAL_INT2_EXTNUM 2 /* (intlevel 1) */ +#define XCHAL_INT3_EXTNUM 3 /* (intlevel 1) */ +#define XCHAL_INT4_EXTNUM 4 /* (intlevel 1) */ +#define XCHAL_INT5_EXTNUM 5 /* (intlevel 1) */ +#define XCHAL_INT8_EXTNUM 6 /* (intlevel 1) */ +#define XCHAL_INT9_EXTNUM 7 /* (intlevel 1) */ +#define XCHAL_INT10_EXTNUM 8 /* (intlevel 1) */ +#define XCHAL_INT12_EXTNUM 9 /* (intlevel 1) */ +#define XCHAL_INT13_EXTNUM 10 /* (intlevel 1) */ +#define XCHAL_INT14_EXTNUM 11 /* (intlevel 7) */ +#define XCHAL_INT17_EXTNUM 12 /* (intlevel 1) */ +#define XCHAL_INT18_EXTNUM 13 /* (intlevel 1) */ +#define XCHAL_INT19_EXTNUM 14 /* (intlevel 2) */ +#define XCHAL_INT20_EXTNUM 15 /* (intlevel 2) */ +#define XCHAL_INT21_EXTNUM 16 /* (intlevel 2) */ +#define XCHAL_INT22_EXTNUM 17 /* (intlevel 3) */ +#define XCHAL_INT23_EXTNUM 18 /* (intlevel 3) */ +#define XCHAL_INT24_EXTNUM 19 /* (intlevel 4) */ +#define XCHAL_INT25_EXTNUM 20 /* (intlevel 4) */ +#define XCHAL_INT26_EXTNUM 21 /* (intlevel 5) */ +#define XCHAL_INT27_EXTNUM 22 /* (intlevel 3) */ +#define XCHAL_INT28_EXTNUM 23 /* (intlevel 4) */ +#define XCHAL_INT30_EXTNUM 24 /* (intlevel 4) */ +#define XCHAL_INT31_EXTNUM 25 /* (intlevel 5) */ + + +/*---------------------------------------------------------------------- + EXCEPTIONS and VECTORS + ----------------------------------------------------------------------*/ + +#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture + number: 1 == XEA1 (old) + 2 == XEA2 (new) + 0 == XEAX (extern) or TX */ +#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */ +#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */ +#define XCHAL_HAVE_XEAX 0 /* External Exception Arch. */ +#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */ +#define XCHAL_HAVE_HALT 0 /* halt architecture option */ +#define XCHAL_HAVE_BOOTLOADER 0 /* boot loader (for TX) */ +#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */ +#define XCHAL_HAVE_VECTOR_SELECT 1 /* relocatable vectors */ +#define XCHAL_HAVE_VECBASE 1 /* relocatable vectors */ +#define XCHAL_VECBASE_RESET_VADDR 0x40000000 /* VECBASE reset value */ +#define XCHAL_VECBASE_RESET_PADDR 0x40000000 +#define XCHAL_RESET_VECBASE_OVERLAP 0 + +#define XCHAL_RESET_VECTOR0_VADDR 0x50000000 +#define XCHAL_RESET_VECTOR0_PADDR 0x50000000 +#define XCHAL_RESET_VECTOR1_VADDR 0x40000400 +#define XCHAL_RESET_VECTOR1_PADDR 0x40000400 +#define XCHAL_RESET_VECTOR_VADDR 0x40000400 +#define XCHAL_RESET_VECTOR_PADDR 0x40000400 +#define XCHAL_USER_VECOFS 0x00000340 +#define XCHAL_USER_VECTOR_VADDR 0x40000340 +#define XCHAL_USER_VECTOR_PADDR 0x40000340 +#define XCHAL_KERNEL_VECOFS 0x00000300 +#define XCHAL_KERNEL_VECTOR_VADDR 0x40000300 +#define XCHAL_KERNEL_VECTOR_PADDR 0x40000300 +#define XCHAL_DOUBLEEXC_VECOFS 0x000003C0 +#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0x400003C0 +#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x400003C0 +#define XCHAL_WINDOW_OF4_VECOFS 0x00000000 +#define XCHAL_WINDOW_UF4_VECOFS 0x00000040 +#define XCHAL_WINDOW_OF8_VECOFS 0x00000080 +#define XCHAL_WINDOW_UF8_VECOFS 0x000000C0 +#define XCHAL_WINDOW_OF12_VECOFS 0x00000100 +#define XCHAL_WINDOW_UF12_VECOFS 0x00000140 +#define XCHAL_WINDOW_VECTORS_VADDR 0x40000000 +#define XCHAL_WINDOW_VECTORS_PADDR 0x40000000 +#define XCHAL_INTLEVEL2_VECOFS 0x00000180 +#define XCHAL_INTLEVEL2_VECTOR_VADDR 0x40000180 +#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x40000180 +#define XCHAL_INTLEVEL3_VECOFS 0x000001C0 +#define XCHAL_INTLEVEL3_VECTOR_VADDR 0x400001C0 +#define XCHAL_INTLEVEL3_VECTOR_PADDR 0x400001C0 +#define XCHAL_INTLEVEL4_VECOFS 0x00000200 +#define XCHAL_INTLEVEL4_VECTOR_VADDR 0x40000200 +#define XCHAL_INTLEVEL4_VECTOR_PADDR 0x40000200 +#define XCHAL_INTLEVEL5_VECOFS 0x00000240 +#define XCHAL_INTLEVEL5_VECTOR_VADDR 0x40000240 +#define XCHAL_INTLEVEL5_VECTOR_PADDR 0x40000240 +#define XCHAL_INTLEVEL6_VECOFS 0x00000280 +#define XCHAL_INTLEVEL6_VECTOR_VADDR 0x40000280 +#define XCHAL_INTLEVEL6_VECTOR_PADDR 0x40000280 +#define XCHAL_DEBUG_VECOFS XCHAL_INTLEVEL6_VECOFS +#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL6_VECTOR_VADDR +#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL6_VECTOR_PADDR +#define XCHAL_NMI_VECOFS 0x000002C0 +#define XCHAL_NMI_VECTOR_VADDR 0x400002C0 +#define XCHAL_NMI_VECTOR_PADDR 0x400002C0 +#define XCHAL_INTLEVEL7_VECOFS XCHAL_NMI_VECOFS +#define XCHAL_INTLEVEL7_VECTOR_VADDR XCHAL_NMI_VECTOR_VADDR +#define XCHAL_INTLEVEL7_VECTOR_PADDR XCHAL_NMI_VECTOR_PADDR + + +/*---------------------------------------------------------------------- + DEBUG MODULE + ----------------------------------------------------------------------*/ + +/* Misc */ +#define XCHAL_HAVE_DEBUG_ERI 1 /* ERI to debug module */ +#define XCHAL_HAVE_DEBUG_APB 1 /* APB to debug module */ +#define XCHAL_HAVE_DEBUG_JTAG 1 /* JTAG to debug module */ + +/* On-Chip Debug (OCD) */ +#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */ +#define XCHAL_NUM_IBREAK 2 /* number of IBREAKn regs */ +#define XCHAL_NUM_DBREAK 2 /* number of DBREAKn regs */ +#define XCHAL_HAVE_OCD_DIR_ARRAY 0 /* faster OCD option (to LX4) */ +#define XCHAL_HAVE_OCD_LS32DDR 1 /* L32DDR/S32DDR (faster OCD) */ + +/* TRAX (in core) */ +#define XCHAL_HAVE_TRAX 1 /* TRAX in debug module */ +#define XCHAL_TRAX_MEM_SIZE 16384 /* TRAX memory size in bytes */ +#define XCHAL_TRAX_MEM_SHAREABLE 1 /* start/end regs; ready sig. */ +#define XCHAL_TRAX_ATB_WIDTH 32 /* ATB width (bits), 0=no ATB */ +#define XCHAL_TRAX_TIME_WIDTH 0 /* timestamp bitwidth, 0=none */ + +/* Perf counters */ +#define XCHAL_NUM_PERF_COUNTERS 2 /* performance counters */ + + +/*---------------------------------------------------------------------- + MMU + ----------------------------------------------------------------------*/ + +/* See core-matmap.h header file for more details. */ + +#define XCHAL_HAVE_TLBS 1 /* inverse of HAVE_CACHEATTR */ +#define XCHAL_HAVE_SPANNING_WAY 1 /* one way maps I+D 4GB vaddr */ +#define XCHAL_SPANNING_WAY 0 /* TLB spanning way number */ +#define XCHAL_HAVE_IDENTITY_MAP 1 /* vaddr == paddr always */ +#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */ +#define XCHAL_HAVE_MIMIC_CACHEATTR 1 /* region protection */ +#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */ +#define XCHAL_HAVE_PTP_MMU 0 /* full MMU (with page table + [autorefill] and protection) + usable for an MMU-based OS */ +/* If none of the above last 4 are set, it's a custom TLB configuration. */ + +#define XCHAL_MMU_ASID_BITS 0 /* number of bits in ASIDs */ +#define XCHAL_MMU_RINGS 1 /* number of rings (1..4) */ +#define XCHAL_MMU_RING_BITS 0 /* num of bits in RING field */ + +#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ + + +#endif /* _XTENSA_CORE_CONFIGURATION_H */ + diff --git a/target/xtensa/core-esp32/gdb-config.inc.c b/target/xtensa/core-esp32/gdb-config.inc.c new file mode 100644 index 000000000000..cf4d7c94cb02 --- /dev/null +++ b/target/xtensa/core-esp32/gdb-config.inc.c @@ -0,0 +1,290 @@ +/* Configuration for the Xtensa architecture for GDB, the GNU debugger. + + Copyright (c) 2003-2016 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + XTREG( 0, 0,32, 4, 4,0x0020,0x0006,-2, 9,0x0100,pc, 0,0,0,0,0,0) + XTREG( 1, 4,32, 4, 4,0x0100,0x0006,-2, 1,0x0002,ar0, 0,0,0,0,0,0) + XTREG( 2, 8,32, 4, 4,0x0101,0x0006,-2, 1,0x0002,ar1, 0,0,0,0,0,0) + XTREG( 3, 12,32, 4, 4,0x0102,0x0006,-2, 1,0x0002,ar2, 0,0,0,0,0,0) + XTREG( 4, 16,32, 4, 4,0x0103,0x0006,-2, 1,0x0002,ar3, 0,0,0,0,0,0) + XTREG( 5, 20,32, 4, 4,0x0104,0x0006,-2, 1,0x0002,ar4, 0,0,0,0,0,0) + XTREG( 6, 24,32, 4, 4,0x0105,0x0006,-2, 1,0x0002,ar5, 0,0,0,0,0,0) + XTREG( 7, 28,32, 4, 4,0x0106,0x0006,-2, 1,0x0002,ar6, 0,0,0,0,0,0) + XTREG( 8, 32,32, 4, 4,0x0107,0x0006,-2, 1,0x0002,ar7, 0,0,0,0,0,0) + XTREG( 9, 36,32, 4, 4,0x0108,0x0006,-2, 1,0x0002,ar8, 0,0,0,0,0,0) + XTREG( 10, 40,32, 4, 4,0x0109,0x0006,-2, 1,0x0002,ar9, 0,0,0,0,0,0) + XTREG( 11, 44,32, 4, 4,0x010a,0x0006,-2, 1,0x0002,ar10, 0,0,0,0,0,0) + XTREG( 12, 48,32, 4, 4,0x010b,0x0006,-2, 1,0x0002,ar11, 0,0,0,0,0,0) + XTREG( 13, 52,32, 4, 4,0x010c,0x0006,-2, 1,0x0002,ar12, 0,0,0,0,0,0) + XTREG( 14, 56,32, 4, 4,0x010d,0x0006,-2, 1,0x0002,ar13, 0,0,0,0,0,0) + XTREG( 15, 60,32, 4, 4,0x010e,0x0006,-2, 1,0x0002,ar14, 0,0,0,0,0,0) + XTREG( 16, 64,32, 4, 4,0x010f,0x0006,-2, 1,0x0002,ar15, 0,0,0,0,0,0) + XTREG( 17, 68,32, 4, 4,0x0110,0x0006,-2, 1,0x0002,ar16, 0,0,0,0,0,0) + XTREG( 18, 72,32, 4, 4,0x0111,0x0006,-2, 1,0x0002,ar17, 0,0,0,0,0,0) + XTREG( 19, 76,32, 4, 4,0x0112,0x0006,-2, 1,0x0002,ar18, 0,0,0,0,0,0) + XTREG( 20, 80,32, 4, 4,0x0113,0x0006,-2, 1,0x0002,ar19, 0,0,0,0,0,0) + XTREG( 21, 84,32, 4, 4,0x0114,0x0006,-2, 1,0x0002,ar20, 0,0,0,0,0,0) + XTREG( 22, 88,32, 4, 4,0x0115,0x0006,-2, 1,0x0002,ar21, 0,0,0,0,0,0) + XTREG( 23, 92,32, 4, 4,0x0116,0x0006,-2, 1,0x0002,ar22, 0,0,0,0,0,0) + XTREG( 24, 96,32, 4, 4,0x0117,0x0006,-2, 1,0x0002,ar23, 0,0,0,0,0,0) + XTREG( 25,100,32, 4, 4,0x0118,0x0006,-2, 1,0x0002,ar24, 0,0,0,0,0,0) + XTREG( 26,104,32, 4, 4,0x0119,0x0006,-2, 1,0x0002,ar25, 0,0,0,0,0,0) + XTREG( 27,108,32, 4, 4,0x011a,0x0006,-2, 1,0x0002,ar26, 0,0,0,0,0,0) + XTREG( 28,112,32, 4, 4,0x011b,0x0006,-2, 1,0x0002,ar27, 0,0,0,0,0,0) + XTREG( 29,116,32, 4, 4,0x011c,0x0006,-2, 1,0x0002,ar28, 0,0,0,0,0,0) + XTREG( 30,120,32, 4, 4,0x011d,0x0006,-2, 1,0x0002,ar29, 0,0,0,0,0,0) + XTREG( 31,124,32, 4, 4,0x011e,0x0006,-2, 1,0x0002,ar30, 0,0,0,0,0,0) + XTREG( 32,128,32, 4, 4,0x011f,0x0006,-2, 1,0x0002,ar31, 0,0,0,0,0,0) + XTREG( 33,132,32, 4, 4,0x0120,0x0006,-2, 1,0x0002,ar32, 0,0,0,0,0,0) + XTREG( 34,136,32, 4, 4,0x0121,0x0006,-2, 1,0x0002,ar33, 0,0,0,0,0,0) + XTREG( 35,140,32, 4, 4,0x0122,0x0006,-2, 1,0x0002,ar34, 0,0,0,0,0,0) + XTREG( 36,144,32, 4, 4,0x0123,0x0006,-2, 1,0x0002,ar35, 0,0,0,0,0,0) + XTREG( 37,148,32, 4, 4,0x0124,0x0006,-2, 1,0x0002,ar36, 0,0,0,0,0,0) + XTREG( 38,152,32, 4, 4,0x0125,0x0006,-2, 1,0x0002,ar37, 0,0,0,0,0,0) + XTREG( 39,156,32, 4, 4,0x0126,0x0006,-2, 1,0x0002,ar38, 0,0,0,0,0,0) + XTREG( 40,160,32, 4, 4,0x0127,0x0006,-2, 1,0x0002,ar39, 0,0,0,0,0,0) + XTREG( 41,164,32, 4, 4,0x0128,0x0006,-2, 1,0x0002,ar40, 0,0,0,0,0,0) + XTREG( 42,168,32, 4, 4,0x0129,0x0006,-2, 1,0x0002,ar41, 0,0,0,0,0,0) + XTREG( 43,172,32, 4, 4,0x012a,0x0006,-2, 1,0x0002,ar42, 0,0,0,0,0,0) + XTREG( 44,176,32, 4, 4,0x012b,0x0006,-2, 1,0x0002,ar43, 0,0,0,0,0,0) + XTREG( 45,180,32, 4, 4,0x012c,0x0006,-2, 1,0x0002,ar44, 0,0,0,0,0,0) + XTREG( 46,184,32, 4, 4,0x012d,0x0006,-2, 1,0x0002,ar45, 0,0,0,0,0,0) + XTREG( 47,188,32, 4, 4,0x012e,0x0006,-2, 1,0x0002,ar46, 0,0,0,0,0,0) + XTREG( 48,192,32, 4, 4,0x012f,0x0006,-2, 1,0x0002,ar47, 0,0,0,0,0,0) + XTREG( 49,196,32, 4, 4,0x0130,0x0006,-2, 1,0x0002,ar48, 0,0,0,0,0,0) + XTREG( 50,200,32, 4, 4,0x0131,0x0006,-2, 1,0x0002,ar49, 0,0,0,0,0,0) + XTREG( 51,204,32, 4, 4,0x0132,0x0006,-2, 1,0x0002,ar50, 0,0,0,0,0,0) + XTREG( 52,208,32, 4, 4,0x0133,0x0006,-2, 1,0x0002,ar51, 0,0,0,0,0,0) + XTREG( 53,212,32, 4, 4,0x0134,0x0006,-2, 1,0x0002,ar52, 0,0,0,0,0,0) + XTREG( 54,216,32, 4, 4,0x0135,0x0006,-2, 1,0x0002,ar53, 0,0,0,0,0,0) + XTREG( 55,220,32, 4, 4,0x0136,0x0006,-2, 1,0x0002,ar54, 0,0,0,0,0,0) + XTREG( 56,224,32, 4, 4,0x0137,0x0006,-2, 1,0x0002,ar55, 0,0,0,0,0,0) + XTREG( 57,228,32, 4, 4,0x0138,0x0006,-2, 1,0x0002,ar56, 0,0,0,0,0,0) + XTREG( 58,232,32, 4, 4,0x0139,0x0006,-2, 1,0x0002,ar57, 0,0,0,0,0,0) + XTREG( 59,236,32, 4, 4,0x013a,0x0006,-2, 1,0x0002,ar58, 0,0,0,0,0,0) + XTREG( 60,240,32, 4, 4,0x013b,0x0006,-2, 1,0x0002,ar59, 0,0,0,0,0,0) + XTREG( 61,244,32, 4, 4,0x013c,0x0006,-2, 1,0x0002,ar60, 0,0,0,0,0,0) + XTREG( 62,248,32, 4, 4,0x013d,0x0006,-2, 1,0x0002,ar61, 0,0,0,0,0,0) + XTREG( 63,252,32, 4, 4,0x013e,0x0006,-2, 1,0x0002,ar62, 0,0,0,0,0,0) + XTREG( 64,256,32, 4, 4,0x013f,0x0006,-2, 1,0x0002,ar63, 0,0,0,0,0,0) + XTREG( 65,260,32, 4, 4,0x0200,0x0006,-2, 2,0x1100,lbeg, 0,0,0,0,0,0) + XTREG( 66,264,32, 4, 4,0x0201,0x0006,-2, 2,0x1100,lend, 0,0,0,0,0,0) + XTREG( 67,268,32, 4, 4,0x0202,0x0006,-2, 2,0x1100,lcount, 0,0,0,0,0,0) + XTREG( 68,272, 6, 4, 4,0x0203,0x0006,-2, 2,0x1100,sar, 0,0,0,0,0,0) + XTREG( 69,276, 4, 4, 4,0x0248,0x0006,-2, 2,0x1002,windowbase, 0,0,0,0,0,0) + XTREG( 70,280,16, 4, 4,0x0249,0x0006,-2, 2,0x1002,windowstart, 0,0,0,0,0,0) + XTREG( 71,284,32, 4, 4,0x02b0,0x0002,-2, 2,0x1000,configid0, 0,0,0,0,0,0) + XTREG( 72,288,32, 4, 4,0x02d0,0x0002,-2, 2,0x1000,configid1, 0,0,0,0,0,0) + XTREG( 73,292,19, 4, 4,0x02e6,0x0006,-2, 2,0x1100,ps, 0,0,0,0,0,0) + XTREG( 74,296,32, 4, 4,0x03e7,0x0006,-2, 3,0x0110,threadptr, 0,0,0,0,0,0) + XTREG( 75,300,16, 4, 4,0x0204,0x0006,-1, 2,0x1100,br, 0,0,0,0,0,0) + XTREG( 76,304,32, 4, 4,0x020c,0x0006,-1, 2,0x1100,scompare1, 0,0,0,0,0,0) + XTREG( 77,308,32, 4, 4,0x0210,0x0006,-1, 2,0x1100,acclo, 0,0,0,0,0,0) + XTREG( 78,312, 8, 4, 4,0x0211,0x0006,-1, 2,0x1100,acchi, 0,0,0,0,0,0) + XTREG( 79,316,32, 4, 4,0x0220,0x0006,-1, 2,0x1100,m0, 0,0,0,0,0,0) + XTREG( 80,320,32, 4, 4,0x0221,0x0006,-1, 2,0x1100,m1, 0,0,0,0,0,0) + XTREG( 81,324,32, 4, 4,0x0222,0x0006,-1, 2,0x1100,m2, 0,0,0,0,0,0) + XTREG( 82,328,32, 4, 4,0x0223,0x0006,-1, 2,0x1100,m3, 0,0,0,0,0,0) + XTREG( 83,332,32, 4, 4,0x03e6,0x000e,-1, 3,0x0110,expstate, 0,0,0,0,0,0) + XTREG( 84,336,32, 4, 4,0x03ea,0x0006,-1, 3,0x0100,f64r_lo, 0,0,0,0,0,0) + XTREG( 85,340,32, 4, 4,0x03eb,0x0006,-1, 3,0x0100,f64r_hi, 0,0,0,0,0,0) + XTREG( 86,344,32, 4, 4,0x03ec,0x0006,-1, 3,0x0110,f64s, 0,0,0,0,0,0) + XTREG( 87,348,32, 4, 4,0x0030,0x0006, 0, 4,0x0401,f0, + "03:03:44:00","03:03:04:00",0,0,0,0) + XTREG( 88,352,32, 4, 4,0x0031,0x0006, 0, 4,0x0401,f1, + "03:13:44:00","03:13:04:00",0,0,0,0) + XTREG( 89,356,32, 4, 4,0x0032,0x0006, 0, 4,0x0401,f2, + "03:23:44:00","03:23:04:00",0,0,0,0) + XTREG( 90,360,32, 4, 4,0x0033,0x0006, 0, 4,0x0401,f3, + "03:33:44:00","03:33:04:00",0,0,0,0) + XTREG( 91,364,32, 4, 4,0x0034,0x0006, 0, 4,0x0401,f4, + "03:43:44:00","03:43:04:00",0,0,0,0) + XTREG( 92,368,32, 4, 4,0x0035,0x0006, 0, 4,0x0401,f5, + "03:53:44:00","03:53:04:00",0,0,0,0) + XTREG( 93,372,32, 4, 4,0x0036,0x0006, 0, 4,0x0401,f6, + "03:63:44:00","03:63:04:00",0,0,0,0) + XTREG( 94,376,32, 4, 4,0x0037,0x0006, 0, 4,0x0401,f7, + "03:73:44:00","03:73:04:00",0,0,0,0) + XTREG( 95,380,32, 4, 4,0x0038,0x0006, 0, 4,0x0401,f8, + "03:83:44:00","03:83:04:00",0,0,0,0) + XTREG( 96,384,32, 4, 4,0x0039,0x0006, 0, 4,0x0401,f9, + "03:93:44:00","03:93:04:00",0,0,0,0) + XTREG( 97,388,32, 4, 4,0x003a,0x0006, 0, 4,0x0401,f10, + "03:a3:44:00","03:a3:04:00",0,0,0,0) + XTREG( 98,392,32, 4, 4,0x003b,0x0006, 0, 4,0x0401,f11, + "03:b3:44:00","03:b3:04:00",0,0,0,0) + XTREG( 99,396,32, 4, 4,0x003c,0x0006, 0, 4,0x0401,f12, + "03:c3:44:00","03:c3:04:00",0,0,0,0) + XTREG(100,400,32, 4, 4,0x003d,0x0006, 0, 4,0x0401,f13, + "03:d3:44:00","03:d3:04:00",0,0,0,0) + XTREG(101,404,32, 4, 4,0x003e,0x0006, 0, 4,0x0401,f14, + "03:e3:44:00","03:e3:04:00",0,0,0,0) + XTREG(102,408,32, 4, 4,0x003f,0x0006, 0, 4,0x0401,f15, + "03:f3:44:00","03:f3:04:00",0,0,0,0) + XTREG(103,412,32, 4, 4,0x03e8,0x0006, 0, 3,0x0100,fcr, 0,0,0,0,0,0) + XTREG(104,416,32, 4, 4,0x03e9,0x0006, 0, 3,0x0100,fsr, 0,0,0,0,0,0) + XTREG(105,420,32, 4, 4,0x0259,0x000d,-2, 2,0x1000,mmid, 0,0,0,0,0,0) + XTREG(106,424, 2, 4, 4,0x0260,0x0007,-2, 2,0x1000,ibreakenable,0,0,0,0,0,0) + XTREG(107,428, 1, 4, 4,0x0261,0x0007,-2, 2,0x1000,memctl, 0,0,0,0,0,0) + XTREG(108,432, 6, 4, 4,0x0263,0x0007,-2, 2,0x1000,atomctl, 0,0,0,0,0,0) + XTREG(109,436,32, 4, 4,0x0268,0x0007,-2, 2,0x1000,ddr, 0,0,0,0,0,0) + XTREG(110,440,32, 4, 4,0x0280,0x0007,-2, 2,0x1000,ibreaka0, 0,0,0,0,0,0) + XTREG(111,444,32, 4, 4,0x0281,0x0007,-2, 2,0x1000,ibreaka1, 0,0,0,0,0,0) + XTREG(112,448,32, 4, 4,0x0290,0x0007,-2, 2,0x1000,dbreaka0, 0,0,0,0,0,0) + XTREG(113,452,32, 4, 4,0x0291,0x0007,-2, 2,0x1000,dbreaka1, 0,0,0,0,0,0) + XTREG(114,456,32, 4, 4,0x02a0,0x0007,-2, 2,0x1000,dbreakc0, 0,0,0,0,0,0) + XTREG(115,460,32, 4, 4,0x02a1,0x0007,-2, 2,0x1000,dbreakc1, 0,0,0,0,0,0) + XTREG(116,464,32, 4, 4,0x02b1,0x0007,-2, 2,0x1000,epc1, 0,0,0,0,0,0) + XTREG(117,468,32, 4, 4,0x02b2,0x0007,-2, 2,0x1000,epc2, 0,0,0,0,0,0) + XTREG(118,472,32, 4, 4,0x02b3,0x0007,-2, 2,0x1000,epc3, 0,0,0,0,0,0) + XTREG(119,476,32, 4, 4,0x02b4,0x0007,-2, 2,0x1000,epc4, 0,0,0,0,0,0) + XTREG(120,480,32, 4, 4,0x02b5,0x0007,-2, 2,0x1000,epc5, 0,0,0,0,0,0) + XTREG(121,484,32, 4, 4,0x02b6,0x0007,-2, 2,0x1000,epc6, 0,0,0,0,0,0) + XTREG(122,488,32, 4, 4,0x02b7,0x0007,-2, 2,0x1000,epc7, 0,0,0,0,0,0) + XTREG(123,492,32, 4, 4,0x02c0,0x0007,-2, 2,0x1000,depc, 0,0,0,0,0,0) + XTREG(124,496,19, 4, 4,0x02c2,0x0007,-2, 2,0x1000,eps2, 0,0,0,0,0,0) + XTREG(125,500,19, 4, 4,0x02c3,0x0007,-2, 2,0x1000,eps3, 0,0,0,0,0,0) + XTREG(126,504,19, 4, 4,0x02c4,0x0007,-2, 2,0x1000,eps4, 0,0,0,0,0,0) + XTREG(127,508,19, 4, 4,0x02c5,0x0007,-2, 2,0x1000,eps5, 0,0,0,0,0,0) + XTREG(128,512,19, 4, 4,0x02c6,0x0007,-2, 2,0x1000,eps6, 0,0,0,0,0,0) + XTREG(129,516,19, 4, 4,0x02c7,0x0007,-2, 2,0x1000,eps7, 0,0,0,0,0,0) + XTREG(130,520,32, 4, 4,0x02d1,0x0007,-2, 2,0x1000,excsave1, 0,0,0,0,0,0) + XTREG(131,524,32, 4, 4,0x02d2,0x0007,-2, 2,0x1000,excsave2, 0,0,0,0,0,0) + XTREG(132,528,32, 4, 4,0x02d3,0x0007,-2, 2,0x1000,excsave3, 0,0,0,0,0,0) + XTREG(133,532,32, 4, 4,0x02d4,0x0007,-2, 2,0x1000,excsave4, 0,0,0,0,0,0) + XTREG(134,536,32, 4, 4,0x02d5,0x0007,-2, 2,0x1000,excsave5, 0,0,0,0,0,0) + XTREG(135,540,32, 4, 4,0x02d6,0x0007,-2, 2,0x1000,excsave6, 0,0,0,0,0,0) + XTREG(136,544,32, 4, 4,0x02d7,0x0007,-2, 2,0x1000,excsave7, 0,0,0,0,0,0) + XTREG(137,548, 8, 4, 4,0x02e0,0x0007,-2, 2,0x1000,cpenable, 0,0,0,0,0,0) + XTREG(138,552,32, 4, 4,0x02e2,0x000b,-2, 2,0x1000,interrupt, 0,0,0,0,0,0) + XTREG(139,556,32, 4, 4,0x02e2,0x000d,-2, 2,0x1000,intset, 0,0,0,0,0,0) + XTREG(140,560,32, 4, 4,0x02e3,0x000d,-2, 2,0x1000,intclear, 0,0,0,0,0,0) + XTREG(141,564,32, 4, 4,0x02e4,0x0007,-2, 2,0x1000,intenable, 0,0,0,0,0,0) + XTREG(142,568,32, 4, 4,0x02e7,0x0007,-2, 2,0x1000,vecbase, 0,0,0,0,0,0) + XTREG(143,572, 6, 4, 4,0x02e8,0x0007,-2, 2,0x1000,exccause, 0,0,0,0,0,0) + XTREG(144,576,12, 4, 4,0x02e9,0x0003,-2, 2,0x1000,debugcause, 0,0,0,0,0,0) + XTREG(145,580,32, 4, 4,0x02ea,0x000f,-2, 2,0x1000,ccount, 0,0,0,0,0,0) + XTREG(146,584,32, 4, 4,0x02eb,0x0003,-2, 2,0x1000,prid, 0,0,0,0,0,0) + XTREG(147,588,32, 4, 4,0x02ec,0x000f,-2, 2,0x1000,icount, 0,0,0,0,0,0) + XTREG(148,592, 4, 4, 4,0x02ed,0x0007,-2, 2,0x1000,icountlevel, 0,0,0,0,0,0) + XTREG(149,596,32, 4, 4,0x02ee,0x0007,-2, 2,0x1000,excvaddr, 0,0,0,0,0,0) + XTREG(150,600,32, 4, 4,0x02f0,0x000f,-2, 2,0x1000,ccompare0, 0,0,0,0,0,0) + XTREG(151,604,32, 4, 4,0x02f1,0x000f,-2, 2,0x1000,ccompare1, 0,0,0,0,0,0) + XTREG(152,608,32, 4, 4,0x02f2,0x000f,-2, 2,0x1000,ccompare2, 0,0,0,0,0,0) + XTREG(153,612,32, 4, 4,0x02f4,0x0007,-2, 2,0x1000,misc0, 0,0,0,0,0,0) + XTREG(154,616,32, 4, 4,0x02f5,0x0007,-2, 2,0x1000,misc1, 0,0,0,0,0,0) + XTREG(155,620,32, 4, 4,0x02f6,0x0007,-2, 2,0x1000,misc2, 0,0,0,0,0,0) + XTREG(156,624,32, 4, 4,0x02f7,0x0007,-2, 2,0x1000,misc3, 0,0,0,0,0,0) + XTREG(157,628,32, 4, 4,0x0000,0x0006,-2, 8,0x0100,a0, 0,0,0,0,0,0) + XTREG(158,632,32, 4, 4,0x0001,0x0006,-2, 8,0x0100,a1, 0,0,0,0,0,0) + XTREG(159,636,32, 4, 4,0x0002,0x0006,-2, 8,0x0100,a2, 0,0,0,0,0,0) + XTREG(160,640,32, 4, 4,0x0003,0x0006,-2, 8,0x0100,a3, 0,0,0,0,0,0) + XTREG(161,644,32, 4, 4,0x0004,0x0006,-2, 8,0x0100,a4, 0,0,0,0,0,0) + XTREG(162,648,32, 4, 4,0x0005,0x0006,-2, 8,0x0100,a5, 0,0,0,0,0,0) + XTREG(163,652,32, 4, 4,0x0006,0x0006,-2, 8,0x0100,a6, 0,0,0,0,0,0) + XTREG(164,656,32, 4, 4,0x0007,0x0006,-2, 8,0x0100,a7, 0,0,0,0,0,0) + XTREG(165,660,32, 4, 4,0x0008,0x0006,-2, 8,0x0100,a8, 0,0,0,0,0,0) + XTREG(166,664,32, 4, 4,0x0009,0x0006,-2, 8,0x0100,a9, 0,0,0,0,0,0) + XTREG(167,668,32, 4, 4,0x000a,0x0006,-2, 8,0x0100,a10, 0,0,0,0,0,0) + XTREG(168,672,32, 4, 4,0x000b,0x0006,-2, 8,0x0100,a11, 0,0,0,0,0,0) + XTREG(169,676,32, 4, 4,0x000c,0x0006,-2, 8,0x0100,a12, 0,0,0,0,0,0) + XTREG(170,680,32, 4, 4,0x000d,0x0006,-2, 8,0x0100,a13, 0,0,0,0,0,0) + XTREG(171,684,32, 4, 4,0x000e,0x0006,-2, 8,0x0100,a14, 0,0,0,0,0,0) + XTREG(172,688,32, 4, 4,0x000f,0x0006,-2, 8,0x0100,a15, 0,0,0,0,0,0) + XTREG(173,692, 1, 1, 1,0x0010,0x0006,-2, 6,0x1010,b0, + 0,0,&xtensa_mask0,0,0,0) + XTREG(174,693, 1, 1, 1,0x0011,0x0006,-2, 6,0x1010,b1, + 0,0,&xtensa_mask1,0,0,0) + XTREG(175,694, 1, 1, 1,0x0012,0x0006,-2, 6,0x1010,b2, + 0,0,&xtensa_mask2,0,0,0) + XTREG(176,695, 1, 1, 1,0x0013,0x0006,-2, 6,0x1010,b3, + 0,0,&xtensa_mask3,0,0,0) + XTREG(177,696, 1, 1, 1,0x0014,0x0006,-2, 6,0x1010,b4, + 0,0,&xtensa_mask4,0,0,0) + XTREG(178,697, 1, 1, 1,0x0015,0x0006,-2, 6,0x1010,b5, + 0,0,&xtensa_mask5,0,0,0) + XTREG(179,698, 1, 1, 1,0x0016,0x0006,-2, 6,0x1010,b6, + 0,0,&xtensa_mask6,0,0,0) + XTREG(180,699, 1, 1, 1,0x0017,0x0006,-2, 6,0x1010,b7, + 0,0,&xtensa_mask7,0,0,0) + XTREG(181,700, 1, 1, 1,0x0018,0x0006,-2, 6,0x1010,b8, + 0,0,&xtensa_mask8,0,0,0) + XTREG(182,701, 1, 1, 1,0x0019,0x0006,-2, 6,0x1010,b9, + 0,0,&xtensa_mask9,0,0,0) + XTREG(183,702, 1, 1, 1,0x001a,0x0006,-2, 6,0x1010,b10, + 0,0,&xtensa_mask10,0,0,0) + XTREG(184,703, 1, 1, 1,0x001b,0x0006,-2, 6,0x1010,b11, + 0,0,&xtensa_mask11,0,0,0) + XTREG(185,704, 1, 1, 1,0x001c,0x0006,-2, 6,0x1010,b12, + 0,0,&xtensa_mask12,0,0,0) + XTREG(186,705, 1, 1, 1,0x001d,0x0006,-2, 6,0x1010,b13, + 0,0,&xtensa_mask13,0,0,0) + XTREG(187,706, 1, 1, 1,0x001e,0x0006,-2, 6,0x1010,b14, + 0,0,&xtensa_mask14,0,0,0) + XTREG(188,707, 1, 1, 1,0x001f,0x0006,-2, 6,0x1010,b15, + 0,0,&xtensa_mask15,0,0,0) + XTREG(189,708, 4, 4, 4,0x2008,0x0006,-2, 6,0x1010,psintlevel, + 0,0,&xtensa_mask16,0,0,0) + XTREG(190,712, 1, 4, 4,0x2009,0x0006,-2, 6,0x1010,psum, + 0,0,&xtensa_mask17,0,0,0) + XTREG(191,716, 1, 4, 4,0x200a,0x0006,-2, 6,0x1010,pswoe, + 0,0,&xtensa_mask18,0,0,0) + XTREG(192,720, 1, 4, 4,0x200b,0x0006,-2, 6,0x1010,psexcm, + 0,0,&xtensa_mask19,0,0,0) + XTREG(193,724, 2, 4, 4,0x200c,0x0006,-2, 6,0x1010,pscallinc, + 0,0,&xtensa_mask20,0,0,0) + XTREG(194,728, 4, 4, 4,0x200d,0x0006,-2, 6,0x1010,psowb, + 0,0,&xtensa_mask21,0,0,0) + XTREG(195,732,40, 8, 4,0x200e,0x0006,-2, 6,0x1010,acc, + 0,0,&xtensa_mask22,0,0,0) + XTREG(196,740, 4, 4, 4,0x2013,0x0006,-2, 6,0x1010,dbnum, + 0,0,&xtensa_mask23,0,0,0) + XTREG(197,744,64, 8, 4,0x2015,0x0006,-2, 5,0x1010,f64r, + 0,0,&xtensa_mask24,0,0,0) + XTREG(198,752, 2, 4, 4,0x2016,0x0006, 0, 5,0x1010,roundmode, + 0,0,&xtensa_mask25,0,0,0) + XTREG(199,756, 1, 4, 4,0x2017,0x0006, 0, 5,0x1010,invalidenable, + 0,0,&xtensa_mask26,0,0,0) + XTREG(200,760, 1, 4, 4,0x2018,0x0006, 0, 5,0x1010,divzeroenable, + 0,0,&xtensa_mask27,0,0,0) + XTREG(201,764, 1, 4, 4,0x2019,0x0006, 0, 5,0x1010,overflowenable, + 0,0,&xtensa_mask28,0,0,0) + XTREG(202,768, 1, 4, 4,0x201a,0x0006, 0, 5,0x1010,underflowenable, + 0,0,&xtensa_mask29,0,0,0) + XTREG(203,772, 1, 4, 4,0x201b,0x0006, 0, 5,0x1010,inexactenable, + 0,0,&xtensa_mask30,0,0,0) + XTREG(204,776, 1, 4, 4,0x201c,0x0006, 0, 5,0x1010,invalidflag, + 0,0,&xtensa_mask31,0,0,0) + XTREG(205,780, 1, 4, 4,0x201d,0x0006, 0, 5,0x1010,divzeroflag, + 0,0,&xtensa_mask32,0,0,0) + XTREG(206,784, 1, 4, 4,0x201e,0x0006, 0, 5,0x1010,overflowflag, + 0,0,&xtensa_mask33,0,0,0) + XTREG(207,788, 1, 4, 4,0x201f,0x0006, 0, 5,0x1010,underflowflag, + 0,0,&xtensa_mask34,0,0,0) + XTREG(208,792, 1, 4, 4,0x2020,0x0006, 0, 5,0x1010,inexactflag, + 0,0,&xtensa_mask35,0,0,0) + XTREG(209,796,20, 4, 4,0x2021,0x0006, 0, 5,0x1010,fpreserved20, + 0,0,&xtensa_mask36,0,0,0) + XTREG(210,800,20, 4, 4,0x2022,0x0006, 0, 5,0x1010,fpreserved20a, + 0,0,&xtensa_mask37,0,0,0) + XTREG(211,804, 5, 4, 4,0x2023,0x0006, 0, 5,0x1010,fpreserved5, + 0,0,&xtensa_mask38,0,0,0) + XTREG_END diff --git a/target/xtensa/core-esp32/xtensa-modules.inc.c b/target/xtensa/core-esp32/xtensa-modules.inc.c new file mode 100644 index 000000000000..1b9d1b905589 --- /dev/null +++ b/target/xtensa/core-esp32/xtensa-modules.inc.c @@ -0,0 +1,19196 @@ +/* Xtensa configuration-specific ISA information. + + Copyright (c) 2003-2016 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "xtensa-isa.h" +#include "xtensa-isa-internal.h" + + +/* Sysregs. */ + +static xtensa_sysreg_internal sysregs[] = { + { "LBEG", 0, 0 }, + { "LEND", 1, 0 }, + { "LCOUNT", 2, 0 }, + { "BR", 4, 0 }, + { "ACCLO", 16, 0 }, + { "ACCHI", 17, 0 }, + { "M0", 32, 0 }, + { "M1", 33, 0 }, + { "M2", 34, 0 }, + { "M3", 35, 0 }, + { "MMID", 89, 0 }, + { "DDR", 104, 0 }, + { "CONFIGID0", 176, 0 }, + { "CONFIGID1", 208, 0 }, + { "INTERRUPT", 226, 0 }, + { "INTCLEAR", 227, 0 }, + { "CCOUNT", 234, 0 }, + { "PRID", 235, 0 }, + { "ICOUNT", 236, 0 }, + { "CCOMPARE0", 240, 0 }, + { "CCOMPARE1", 241, 0 }, + { "CCOMPARE2", 242, 0 }, + { "VECBASE", 231, 0 }, + { "EPC1", 177, 0 }, + { "EPC2", 178, 0 }, + { "EPC3", 179, 0 }, + { "EPC4", 180, 0 }, + { "EPC5", 181, 0 }, + { "EPC6", 182, 0 }, + { "EPC7", 183, 0 }, + { "EXCSAVE1", 209, 0 }, + { "EXCSAVE2", 210, 0 }, + { "EXCSAVE3", 211, 0 }, + { "EXCSAVE4", 212, 0 }, + { "EXCSAVE5", 213, 0 }, + { "EXCSAVE6", 214, 0 }, + { "EXCSAVE7", 215, 0 }, + { "EPS2", 194, 0 }, + { "EPS3", 195, 0 }, + { "EPS4", 196, 0 }, + { "EPS5", 197, 0 }, + { "EPS6", 198, 0 }, + { "EPS7", 199, 0 }, + { "EXCCAUSE", 232, 0 }, + { "DEPC", 192, 0 }, + { "EXCVADDR", 238, 0 }, + { "WINDOWBASE", 72, 0 }, + { "WINDOWSTART", 73, 0 }, + { "MEMCTL", 97, 0 }, + { "SAR", 3, 0 }, + { "PS", 230, 0 }, + { "MISC0", 244, 0 }, + { "MISC1", 245, 0 }, + { "MISC2", 246, 0 }, + { "MISC3", 247, 0 }, + { "INTENABLE", 228, 0 }, + { "DBREAKA0", 144, 0 }, + { "DBREAKC0", 160, 0 }, + { "DBREAKA1", 145, 0 }, + { "DBREAKC1", 161, 0 }, + { "IBREAKA0", 128, 0 }, + { "IBREAKA1", 129, 0 }, + { "IBREAKENABLE", 96, 0 }, + { "ICOUNTLEVEL", 237, 0 }, + { "DEBUGCAUSE", 233, 0 }, + { "CPENABLE", 224, 0 }, + { "SCOMPARE1", 12, 0 }, + { "ATOMCTL", 99, 0 }, + { "THREADPTR", 231, 1 }, + { "F64R_LO", 234, 1 }, + { "F64R_HI", 235, 1 }, + { "F64S", 236, 1 }, + { "FCR", 232, 1 }, + { "FSR", 233, 1 }, + { "EXPSTATE", 230, 1 } +}; + +#define NUM_SYSREGS 75 +#define MAX_SPECIAL_REG 247 +#define MAX_USER_REG 236 + + +/* Processor states. */ + +static xtensa_state_internal states[] = { + { "LCOUNT", 32, 0 }, + { "PC", 32, 0 }, + { "ICOUNT", 32, 0 }, + { "DDR", 32, 0 }, + { "INTERRUPT", 32, 0 }, + { "CCOUNT", 32, 0 }, + { "XTSYNC", 1, 0 }, + { "VECBASE", 22, 0 }, + { "EPC1", 32, 0 }, + { "EPC2", 32, 0 }, + { "EPC3", 32, 0 }, + { "EPC4", 32, 0 }, + { "EPC5", 32, 0 }, + { "EPC6", 32, 0 }, + { "EPC7", 32, 0 }, + { "EXCSAVE1", 32, 0 }, + { "EXCSAVE2", 32, 0 }, + { "EXCSAVE3", 32, 0 }, + { "EXCSAVE4", 32, 0 }, + { "EXCSAVE5", 32, 0 }, + { "EXCSAVE6", 32, 0 }, + { "EXCSAVE7", 32, 0 }, + { "EPS2", 13, 0 }, + { "EPS3", 13, 0 }, + { "EPS4", 13, 0 }, + { "EPS5", 13, 0 }, + { "EPS6", 13, 0 }, + { "EPS7", 13, 0 }, + { "EXCCAUSE", 6, 0 }, + { "PSINTLEVEL", 4, 0 }, + { "PSUM", 1, 0 }, + { "PSWOE", 1, 0 }, + { "PSEXCM", 1, 0 }, + { "DEPC", 32, 0 }, + { "EXCVADDR", 32, 0 }, + { "WindowBase", 4, 0 }, + { "WindowStart", 16, 0 }, + { "PSCALLINC", 2, 0 }, + { "PSOWB", 4, 0 }, + { "LBEG", 32, 0 }, + { "LEND", 32, 0 }, + { "MEMCTL", 1, 0 }, + { "SAR", 6, 0 }, + { "THREADPTR", 32, 0 }, + { "MISC0", 32, 0 }, + { "MISC1", 32, 0 }, + { "MISC2", 32, 0 }, + { "MISC3", 32, 0 }, + { "ACC", 40, 0 }, + { "InOCDMode", 1, 0 }, + { "INTENABLE", 32, 0 }, + { "DBREAKA0", 32, 0 }, + { "DBREAKC0", 8, 0 }, + { "DBREAKA1", 32, 0 }, + { "DBREAKC1", 8, 0 }, + { "IBREAKA0", 32, 0 }, + { "IBREAKA1", 32, 0 }, + { "IBREAKENABLE", 2, 0 }, + { "ICOUNTLEVEL", 4, 0 }, + { "DEBUGCAUSE", 6, 0 }, + { "DBNUM", 4, 0 }, + { "CCOMPARE0", 32, 0 }, + { "CCOMPARE1", 32, 0 }, + { "CCOMPARE2", 32, 0 }, + { "CPENABLE", 8, 0 }, + { "SCOMPARE1", 32, 0 }, + { "ATOMCTL", 6, 0 }, + { "ERI_RAW_INTERLOCK", 1, 0 }, + { "F64R", 64, 0 }, + { "F64S", 32, 0 }, + { "RoundMode", 2, 0 }, + { "InvalidEnable", 1, 0 }, + { "DivZeroEnable", 1, 0 }, + { "OverflowEnable", 1, 0 }, + { "UnderflowEnable", 1, 0 }, + { "InexactEnable", 1, 0 }, + { "InvalidFlag", 1, XTENSA_STATE_IS_SHARED_OR }, + { "DivZeroFlag", 1, XTENSA_STATE_IS_SHARED_OR }, + { "OverflowFlag", 1, XTENSA_STATE_IS_SHARED_OR }, + { "UnderflowFlag", 1, XTENSA_STATE_IS_SHARED_OR }, + { "InexactFlag", 1, XTENSA_STATE_IS_SHARED_OR }, + { "FPreserved20", 20, 0 }, + { "FPreserved20a", 20, 0 }, + { "FPreserved5", 5, 0 }, + { "FPreserved7", 7, 0 }, + { "EXPSTATE", 32, XTENSA_STATE_IS_EXPORTED } +}; + +#define NUM_STATES 86 + +enum xtensa_state_id { + STATE_LCOUNT, + STATE_PC, + STATE_ICOUNT, + STATE_DDR, + STATE_INTERRUPT, + STATE_CCOUNT, + STATE_XTSYNC, + STATE_VECBASE, + STATE_EPC1, + STATE_EPC2, + STATE_EPC3, + STATE_EPC4, + STATE_EPC5, + STATE_EPC6, + STATE_EPC7, + STATE_EXCSAVE1, + STATE_EXCSAVE2, + STATE_EXCSAVE3, + STATE_EXCSAVE4, + STATE_EXCSAVE5, + STATE_EXCSAVE6, + STATE_EXCSAVE7, + STATE_EPS2, + STATE_EPS3, + STATE_EPS4, + STATE_EPS5, + STATE_EPS6, + STATE_EPS7, + STATE_EXCCAUSE, + STATE_PSINTLEVEL, + STATE_PSUM, + STATE_PSWOE, + STATE_PSEXCM, + STATE_DEPC, + STATE_EXCVADDR, + STATE_WindowBase, + STATE_WindowStart, + STATE_PSCALLINC, + STATE_PSOWB, + STATE_LBEG, + STATE_LEND, + STATE_MEMCTL, + STATE_SAR, + STATE_THREADPTR, + STATE_MISC0, + STATE_MISC1, + STATE_MISC2, + STATE_MISC3, + STATE_ACC, + STATE_InOCDMode, + STATE_INTENABLE, + STATE_DBREAKA0, + STATE_DBREAKC0, + STATE_DBREAKA1, + STATE_DBREAKC1, + STATE_IBREAKA0, + STATE_IBREAKA1, + STATE_IBREAKENABLE, + STATE_ICOUNTLEVEL, + STATE_DEBUGCAUSE, + STATE_DBNUM, + STATE_CCOMPARE0, + STATE_CCOMPARE1, + STATE_CCOMPARE2, + STATE_CPENABLE, + STATE_SCOMPARE1, + STATE_ATOMCTL, + STATE_ERI_RAW_INTERLOCK, + STATE_F64R, + STATE_F64S, + STATE_RoundMode, + STATE_InvalidEnable, + STATE_DivZeroEnable, + STATE_OverflowEnable, + STATE_UnderflowEnable, + STATE_InexactEnable, + STATE_InvalidFlag, + STATE_DivZeroFlag, + STATE_OverflowFlag, + STATE_UnderflowFlag, + STATE_InexactFlag, + STATE_FPreserved20, + STATE_FPreserved20a, + STATE_FPreserved5, + STATE_FPreserved7, + STATE_EXPSTATE +}; + + +/* Field definitions. */ + +static unsigned +Field_r_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_op0_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_op2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 8) >> 28); + return tie_t; +} + +static void +Field_op2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00000) | (tie_t << 20); +} + +static unsigned +Field_op1_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 12) >> 28); + return tie_t; +} + +static void +Field_op1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0000) | (tie_t << 16); +} + +static unsigned +Field_t_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_s_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_n_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_n_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_m_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 24) >> 30); + return tie_t; +} + +static void +Field_m_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc0) | (tie_t << 6); +} + +static unsigned +Field_sr_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_st_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_thi3_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 24) >> 29); + return tie_t; +} + +static void +Field_thi3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe0) | (tie_t << 5); +} + +static unsigned +Field_t3_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_t3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_tlo_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_tlo_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_w_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 18) >> 30); + return tie_t; +} + +static void +Field_w_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x3000) | (tie_t << 12); +} + +static unsigned +Field_r3_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 16) >> 31); + return tie_t; +} + +static void +Field_r3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x8000) | (tie_t << 15); +} + +static unsigned +Field_rhi_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 16) >> 30); + return tie_t; +} + +static void +Field_rhi_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc000) | (tie_t << 14); +} + +static unsigned +Field_dfp_fld_op2_3_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 8) >> 31); + return tie_t; +} + +static void +Field_dfp_fld_op2_3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x800000) | (tie_t << 23); +} + +static unsigned +Field_dfp_fld_op1_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 12) >> 28); + return tie_t; +} + +static void +Field_dfp_fld_op1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0000) | (tie_t << 16); +} + +static unsigned +Field_dfp_fld_op2_3_2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 8) >> 30); + return tie_t; +} + +static void +Field_dfp_fld_op2_3_2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc00000) | (tie_t << 22); +} + +static unsigned +Field_dfp_fld_r_3_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 16) >> 31); + return tie_t; +} + +static void +Field_dfp_fld_r_3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x8000) | (tie_t << 15); +} + +static unsigned +Field_dfp_fld_op2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 8) >> 28); + return tie_t; +} + +static void +Field_dfp_fld_op2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00000) | (tie_t << 20); +} + +static unsigned +Field_dfp_fld_op2_3_1_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 8) >> 29); + return tie_t; +} + +static void +Field_dfp_fld_op2_3_1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00000) | (tie_t << 21); +} + +static unsigned +Field_dfp_fld_s_3_1_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_dfp_fld_s_3_1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static unsigned +Field_dfp_fld_r_3_1_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 16) >> 29); + return tie_t; +} + +static void +Field_dfp_fld_r_3_1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe000) | (tie_t << 13); +} + +static unsigned +Field_s3to1_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_s3to1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static unsigned +Field_op0_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_t_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_r_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_op0_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_z_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_z_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_i_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_i_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_s_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_t_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_bbi4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 19) >> 31); + return tie_t; +} + +static void +Field_bbi4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x1000) | (tie_t << 12); +} + +static unsigned +Field_bbi_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 19) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_bbi_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x1000) | (tie_t << 12); +} + +static unsigned +Field_imm12_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 12) | ((insn[0] << 8) >> 20); + return tie_t; +} + +static void +Field_imm12_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 20) >> 20; + insn[0] = (insn[0] & ~0xfff000) | (tie_t << 12); +} + +static unsigned +Field_imm8_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 8) | ((insn[0] << 8) >> 24); + return tie_t; +} + +static void +Field_imm8_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 24) >> 24; + insn[0] = (insn[0] & ~0xff0000) | (tie_t << 16); +} + +static unsigned +Field_s_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm12b_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 8) | ((insn[0] << 8) >> 24); + return tie_t; +} + +static void +Field_imm12b_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 24) >> 24; + insn[0] = (insn[0] & ~0xff0000) | (tie_t << 16); + tie_t = (val << 20) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm16_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 16) | ((insn[0] << 8) >> 16); + return tie_t; +} + +static void +Field_imm16_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 16) >> 16; + insn[0] = (insn[0] & ~0xffff00) | (tie_t << 8); +} + +static unsigned +Field_offset_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 18) | ((insn[0] << 8) >> 14); + return tie_t; +} + +static void +Field_offset_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 14) >> 14; + insn[0] = (insn[0] & ~0xffffc0) | (tie_t << 6); +} + +static unsigned +Field_r_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_sa4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + return tie_t; +} + +static void +Field_sa4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sae4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 15) >> 31); + return tie_t; +} + +static void +Field_sae4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x10000) | (tie_t << 16); +} + +static unsigned +Field_sae_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 15) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sae_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x10000) | (tie_t << 16); +} + +static unsigned +Field_sal_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_sal_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sargt_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sargt_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sas4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 27) >> 31); + return tie_t; +} + +static void +Field_sas4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x10) | (tie_t << 4); +} + +static unsigned +Field_sas_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 27) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sas_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x10) | (tie_t << 4); +} + +static unsigned +Field_sr_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_sr_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_st_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_st_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm4_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm4_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_mn_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 24) >> 30); + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_mn_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); + tie_t = (val << 28) >> 30; + insn[0] = (insn[0] & ~0xc0) | (tie_t << 6); +} + +static unsigned +Field_i_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_i_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_imm6lo_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6lo_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm6lo_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6lo_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm6hi_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_imm6hi_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm6hi_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_imm6hi_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm7lo_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7lo_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm7lo_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7lo_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm7hi_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + return tie_t; +} + +static void +Field_imm7hi_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_imm7hi_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + return tie_t; +} + +static void +Field_imm7hi_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_z_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_z_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_imm6_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 26) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm6_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 26) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm7_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 25) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_imm7_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 25) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_rbit2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 17) >> 31); + return tie_t; +} + +static void +Field_rbit2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x4000) | (tie_t << 14); +} + +static unsigned +Field_tbit2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_tbit2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_y_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_y_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_x_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 17) >> 31); + return tie_t; +} + +static void +Field_x_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x4000) | (tie_t << 14); +} + +static unsigned +Field_t2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 24) >> 29); + return tie_t; +} + +static void +Field_t2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe0) | (tie_t << 5); +} + +static unsigned +Field_t2_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 24) >> 29); + return tie_t; +} + +static void +Field_t2_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe0) | (tie_t << 5); +} + +static unsigned +Field_t2_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 24) >> 29); + return tie_t; +} + +static void +Field_t2_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe0) | (tie_t << 5); +} + +static unsigned +Field_s2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_s2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static unsigned +Field_s2_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_s2_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static unsigned +Field_s2_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_s2_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static unsigned +Field_r2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 16) >> 29); + return tie_t; +} + +static void +Field_r2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe000) | (tie_t << 13); +} + +static unsigned +Field_r2_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 16) >> 29); + return tie_t; +} + +static void +Field_r2_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe000) | (tie_t << 13); +} + +static unsigned +Field_r2_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 16) >> 29); + return tie_t; +} + +static void +Field_r2_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe000) | (tie_t << 13); +} + +static unsigned +Field_t4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 24) >> 30); + return tie_t; +} + +static void +Field_t4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc0) | (tie_t << 6); +} + +static unsigned +Field_t4_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 24) >> 30); + return tie_t; +} + +static void +Field_t4_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc0) | (tie_t << 6); +} + +static unsigned +Field_t4_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 24) >> 30); + return tie_t; +} + +static void +Field_t4_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc0) | (tie_t << 6); +} + +static unsigned +Field_s4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 20) >> 30); + return tie_t; +} + +static void +Field_s4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc00) | (tie_t << 10); +} + +static unsigned +Field_s4_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 20) >> 30); + return tie_t; +} + +static void +Field_s4_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc00) | (tie_t << 10); +} + +static unsigned +Field_s4_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 20) >> 30); + return tie_t; +} + +static void +Field_s4_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc00) | (tie_t << 10); +} + +static unsigned +Field_r4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 16) >> 30); + return tie_t; +} + +static void +Field_r4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc000) | (tie_t << 14); +} + +static unsigned +Field_r4_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 16) >> 30); + return tie_t; +} + +static void +Field_r4_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc000) | (tie_t << 14); +} + +static unsigned +Field_r4_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 16) >> 30); + return tie_t; +} + +static void +Field_r4_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc000) | (tie_t << 14); +} + +static unsigned +Field_t8_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_t8_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_t8_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_t8_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_t8_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_t8_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_s8_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 20) >> 31); + return tie_t; +} + +static void +Field_s8_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x800) | (tie_t << 11); +} + +static unsigned +Field_s8_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 20) >> 31); + return tie_t; +} + +static void +Field_s8_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x800) | (tie_t << 11); +} + +static unsigned +Field_s8_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 20) >> 31); + return tie_t; +} + +static void +Field_s8_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x800) | (tie_t << 11); +} + +static unsigned +Field_r8_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 16) >> 31); + return tie_t; +} + +static void +Field_r8_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x8000) | (tie_t << 15); +} + +static unsigned +Field_r8_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 16) >> 31); + return tie_t; +} + +static void +Field_r8_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x8000) | (tie_t << 15); +} + +static unsigned +Field_r8_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 16) >> 31); + return tie_t; +} + +static void +Field_r8_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x8000) | (tie_t << 15); +} + +static unsigned +Field_xt_wbr15_imm_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 15) | ((insn[0] << 8) >> 17); + return tie_t; +} + +static void +Field_xt_wbr15_imm_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 17) >> 17; + insn[0] = (insn[0] & ~0xfffe00) | (tie_t << 9); +} + +static unsigned +Field_xt_wbr18_imm_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 18) | ((insn[0] << 8) >> 14); + return tie_t; +} + +static void +Field_xt_wbr18_imm_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 14) >> 14; + insn[0] = (insn[0] & ~0xffffc0) | (tie_t << 6); +} + +static unsigned +Field_dfp_fld_r_0_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 19) >> 31); + return tie_t; +} + +static void +Field_dfp_fld_r_0_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x1000) | (tie_t << 12); +} + +static unsigned +Field_dfp_fld_r_0_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 19) >> 31); + return tie_t; +} + +static void +Field_dfp_fld_r_0_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x1000) | (tie_t << 12); +} + +static unsigned +Field_dfp_fld_r_0_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 19) >> 31); + return tie_t; +} + +static void +Field_dfp_fld_r_0_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x1000) | (tie_t << 12); +} + +static unsigned +Field_dfp_fld_r_2_1_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 17) >> 30); + return tie_t; +} + +static void +Field_dfp_fld_r_2_1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x6000) | (tie_t << 13); +} + +static unsigned +Field_dfp_fld_r_2_1_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 17) >> 30); + return tie_t; +} + +static void +Field_dfp_fld_r_2_1_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x6000) | (tie_t << 13); +} + +static unsigned +Field_dfp_fld_r_2_1_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 17) >> 30); + return tie_t; +} + +static void +Field_dfp_fld_r_2_1_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x6000) | (tie_t << 13); +} + +static unsigned +Field_dfp_fld_r_3_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 16) >> 31); + return tie_t; +} + +static void +Field_dfp_fld_r_3_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x8000) | (tie_t << 15); +} + +static unsigned +Field_dfp_fld_r_3_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 16) >> 31); + return tie_t; +} + +static void +Field_dfp_fld_r_3_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x8000) | (tie_t << 15); +} + +static unsigned +Field_dfp_fld_r_3_1_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 16) >> 29); + return tie_t; +} + +static void +Field_dfp_fld_r_3_1_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe000) | (tie_t << 13); +} + +static unsigned +Field_dfp_fld_r_3_1_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 16) >> 29); + return tie_t; +} + +static void +Field_dfp_fld_r_3_1_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe000) | (tie_t << 13); +} + +static unsigned +Field_dfp_fld_s_0_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + return tie_t; +} + +static void +Field_dfp_fld_s_0_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); +} + +static unsigned +Field_dfp_fld_s_0_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + return tie_t; +} + +static void +Field_dfp_fld_s_0_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); +} + +static unsigned +Field_dfp_fld_s_0_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + return tie_t; +} + +static void +Field_dfp_fld_s_0_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); +} + +static unsigned +Field_dfp_fld_s_3_1_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_dfp_fld_s_3_1_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static unsigned +Field_dfp_fld_s_3_1_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_dfp_fld_s_3_1_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static unsigned +Field_dfp_fld_op2_0_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + return tie_t; +} + +static void +Field_dfp_fld_op2_0_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_dfp_fld_op2_1_0_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 10) >> 30); + return tie_t; +} + +static void +Field_dfp_fld_op2_1_0_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x300000) | (tie_t << 20); +} + +static unsigned +Field_dfp_fld_op2_2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 9) >> 31); + return tie_t; +} + +static void +Field_dfp_fld_op2_2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x400000) | (tie_t << 22); +} + +static unsigned +Field_bitindex_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_bitindex_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); +} + +static unsigned +Field_bitindex_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_bitindex_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); +} + +static unsigned +Field_bitindex_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_bitindex_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); +} + +static unsigned +Field_s3to1_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_s3to1_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static unsigned +Field_s3to1_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_s3to1_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static void +Implicit_Field_set (xtensa_insnbuf insn ATTRIBUTE_UNUSED, + uint32 val ATTRIBUTE_UNUSED) +{ + /* Do nothing. */ +} + +static unsigned +Implicit_Field_ar0_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 0; +} + +static unsigned +Implicit_Field_ar4_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 4; +} + +static unsigned +Implicit_Field_ar8_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 8; +} + +static unsigned +Implicit_Field_ar12_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 12; +} + +static unsigned +Implicit_Field_mr0_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 0; +} + +static unsigned +Implicit_Field_mr1_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 1; +} + +static unsigned +Implicit_Field_mr2_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 2; +} + +static unsigned +Implicit_Field_mr3_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 3; +} + +static unsigned +Implicit_Field_bt16_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 0; +} + +static unsigned +Implicit_Field_bs16_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 0; +} + +static unsigned +Implicit_Field_br16_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 0; +} + +static unsigned +Implicit_Field_brall_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 0; +} + +enum xtensa_field_id { + FIELD_t, + FIELD_bbi4, + FIELD_bbi, + FIELD_imm12, + FIELD_imm8, + FIELD_s, + FIELD_imm12b, + FIELD_imm16, + FIELD_m, + FIELD_n, + FIELD_offset, + FIELD_op0, + FIELD_op1, + FIELD_op2, + FIELD_r, + FIELD_sa4, + FIELD_sae4, + FIELD_sae, + FIELD_sal, + FIELD_sargt, + FIELD_sas4, + FIELD_sas, + FIELD_sr, + FIELD_st, + FIELD_thi3, + FIELD_imm4, + FIELD_mn, + FIELD_i, + FIELD_imm6lo, + FIELD_imm6hi, + FIELD_imm7lo, + FIELD_imm7hi, + FIELD_z, + FIELD_imm6, + FIELD_imm7, + FIELD_r3, + FIELD_rbit2, + FIELD_rhi, + FIELD_t3, + FIELD_tbit2, + FIELD_tlo, + FIELD_w, + FIELD_y, + FIELD_x, + FIELD_t2, + FIELD_s2, + FIELD_r2, + FIELD_t4, + FIELD_s4, + FIELD_r4, + FIELD_t8, + FIELD_s8, + FIELD_r8, + FIELD_xt_wbr15_imm, + FIELD_xt_wbr18_imm, + FIELD_dfp_fld_op1, + FIELD_dfp_fld_op2, + FIELD_dfp_fld_r_0, + FIELD_dfp_fld_r_2_1, + FIELD_dfp_fld_r_3, + FIELD_dfp_fld_r_3_1, + FIELD_dfp_fld_s_0, + FIELD_dfp_fld_s_3_1, + FIELD_dfp_fld_op2_0, + FIELD_dfp_fld_op2_1_0, + FIELD_dfp_fld_op2_2, + FIELD_dfp_fld_op2_3, + FIELD_dfp_fld_op2_3_2, + FIELD_dfp_fld_op2_3_1, + FIELD_bitindex, + FIELD_s3to1, + FIELD__ar0, + FIELD__ar4, + FIELD__ar8, + FIELD__ar12, + FIELD__mr0, + FIELD__mr1, + FIELD__mr2, + FIELD__mr3, + FIELD__bt16, + FIELD__bs16, + FIELD__br16, + FIELD__brall +}; + + +/* Functional units. */ + +#define funcUnits 0 + + +/* Register files. */ + +enum xtensa_regfile_id { + REGFILE_AR, + REGFILE_MR, + REGFILE_BR, + REGFILE_FR, + REGFILE_BR2, + REGFILE_BR4, + REGFILE_BR8, + REGFILE_BR16 +}; + +static xtensa_regfile_internal regfiles[] = { + { "AR", "a", REGFILE_AR, 32, 64 }, + { "MR", "m", REGFILE_MR, 32, 4 }, + { "BR", "b", REGFILE_BR, 1, 16 }, + { "FR", "f", REGFILE_FR, 32, 16 }, + { "BR2", "b", REGFILE_BR, 2, 8 }, + { "BR4", "b", REGFILE_BR, 4, 4 }, + { "BR8", "b", REGFILE_BR, 8, 2 }, + { "BR16", "b", REGFILE_BR, 16, 1 } +}; + + +/* Interfaces. */ + +static xtensa_interface_internal interfaces[] = { + { "ERI_RD_Out", 14, 0, 0, 'o' }, + { "ERI_RD_In", 32, 0, 1, 'i' }, + { "ERI_RD_Rdy", 1, 0, 0, 'i' }, + { "ERI_WR_Out", 46, 0, 2, 'o' }, + { "ERI_WR_In", 1, 0, 3, 'i' }, + { "IMPWIRE", 32, 0, 4, 'i' } +}; + +enum xtensa_interface_id { + INTERFACE_ERI_RD_Out, + INTERFACE_ERI_RD_In, + INTERFACE_ERI_RD_Rdy, + INTERFACE_ERI_WR_Out, + INTERFACE_ERI_WR_In, + INTERFACE_IMPWIRE +}; + + +/* Constant tables. */ + +/* constant table ai4c */ +static const unsigned CONST_TBL_ai4c_0[] = { + 0xffffffff, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0x9, + 0xa, + 0xb, + 0xc, + 0xd, + 0xe, + 0xf, + 0 +}; + +/* constant table b4c */ +static const unsigned CONST_TBL_b4c_0[] = { + 0xffffffff, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0xa, + 0xc, + 0x10, + 0x20, + 0x40, + 0x80, + 0x100, + 0 +}; + +/* constant table b4cu */ +static const unsigned CONST_TBL_b4cu_0[] = { + 0x8000, + 0x10000, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0xa, + 0xc, + 0x10, + 0x20, + 0x40, + 0x80, + 0x100, + 0 +}; + +/* constant table RECIP_Data8 */ +static const unsigned CONST_TBL_RECIP_Data8_0[] = { + 0xff & 0xff, + 0xfd & 0xff, + 0xfb & 0xff, + 0xf9 & 0xff, + 0xf7 & 0xff, + 0xf5 & 0xff, + 0xf4 & 0xff, + 0xf2 & 0xff, + 0xf0 & 0xff, + 0xee & 0xff, + 0xed & 0xff, + 0xeb & 0xff, + 0xe9 & 0xff, + 0xe8 & 0xff, + 0xe6 & 0xff, + 0xe4 & 0xff, + 0xe3 & 0xff, + 0xe1 & 0xff, + 0xe0 & 0xff, + 0xde & 0xff, + 0xdd & 0xff, + 0xdb & 0xff, + 0xda & 0xff, + 0xd8 & 0xff, + 0xd7 & 0xff, + 0xd5 & 0xff, + 0xd4 & 0xff, + 0xd3 & 0xff, + 0xd1 & 0xff, + 0xd0 & 0xff, + 0xcf & 0xff, + 0xcd & 0xff, + 0xcc & 0xff, + 0xcb & 0xff, + 0xca & 0xff, + 0xc8 & 0xff, + 0xc7 & 0xff, + 0xc6 & 0xff, + 0xc5 & 0xff, + 0xc4 & 0xff, + 0xc2 & 0xff, + 0xc1 & 0xff, + 0xc0 & 0xff, + 0xbf & 0xff, + 0xbe & 0xff, + 0xbd & 0xff, + 0xbc & 0xff, + 0xbb & 0xff, + 0xba & 0xff, + 0xb9 & 0xff, + 0xb8 & 0xff, + 0xb7 & 0xff, + 0xb6 & 0xff, + 0xb5 & 0xff, + 0xb4 & 0xff, + 0xb3 & 0xff, + 0xb2 & 0xff, + 0xb1 & 0xff, + 0xb0 & 0xff, + 0xaf & 0xff, + 0xae & 0xff, + 0xad & 0xff, + 0xac & 0xff, + 0xab & 0xff, + 0xaa & 0xff, + 0xa9 & 0xff, + 0xa8 & 0xff, + 0xa8 & 0xff, + 0xa7 & 0xff, + 0xa6 & 0xff, + 0xa5 & 0xff, + 0xa4 & 0xff, + 0xa3 & 0xff, + 0xa3 & 0xff, + 0xa2 & 0xff, + 0xa1 & 0xff, + 0xa0 & 0xff, + 0x9f & 0xff, + 0x9f & 0xff, + 0x9e & 0xff, + 0x9d & 0xff, + 0x9c & 0xff, + 0x9c & 0xff, + 0x9b & 0xff, + 0x9a & 0xff, + 0x99 & 0xff, + 0x99 & 0xff, + 0x98 & 0xff, + 0x97 & 0xff, + 0x97 & 0xff, + 0x96 & 0xff, + 0x95 & 0xff, + 0x95 & 0xff, + 0x94 & 0xff, + 0x93 & 0xff, + 0x93 & 0xff, + 0x92 & 0xff, + 0x91 & 0xff, + 0x91 & 0xff, + 0x90 & 0xff, + 0x8f & 0xff, + 0x8f & 0xff, + 0x8e & 0xff, + 0x8e & 0xff, + 0x8d & 0xff, + 0x8c & 0xff, + 0x8c & 0xff, + 0x8b & 0xff, + 0x8b & 0xff, + 0x8a & 0xff, + 0x89 & 0xff, + 0x89 & 0xff, + 0x88 & 0xff, + 0x88 & 0xff, + 0x87 & 0xff, + 0x87 & 0xff, + 0x86 & 0xff, + 0x85 & 0xff, + 0x85 & 0xff, + 0x84 & 0xff, + 0x84 & 0xff, + 0x83 & 0xff, + 0x83 & 0xff, + 0x82 & 0xff, + 0x82 & 0xff, + 0x81 & 0xff, + 0x81 & 0xff, + 0x81 & 0xff, + 0 +}; + +/* constant table RSQRT_Data8 */ +static const unsigned CONST_TBL_RSQRT_Data8_0[] = { + 0xb4 & 0xff, + 0xb3 & 0xff, + 0xb2 & 0xff, + 0xb0 & 0xff, + 0xaf & 0xff, + 0xae & 0xff, + 0xac & 0xff, + 0xab & 0xff, + 0xaa & 0xff, + 0xa9 & 0xff, + 0xa8 & 0xff, + 0xa7 & 0xff, + 0xa6 & 0xff, + 0xa5 & 0xff, + 0xa3 & 0xff, + 0xa2 & 0xff, + 0xa1 & 0xff, + 0xa0 & 0xff, + 0x9f & 0xff, + 0x9e & 0xff, + 0x9e & 0xff, + 0x9d & 0xff, + 0x9c & 0xff, + 0x9b & 0xff, + 0x9a & 0xff, + 0x99 & 0xff, + 0x98 & 0xff, + 0x97 & 0xff, + 0x97 & 0xff, + 0x96 & 0xff, + 0x95 & 0xff, + 0x94 & 0xff, + 0x93 & 0xff, + 0x93 & 0xff, + 0x92 & 0xff, + 0x91 & 0xff, + 0x90 & 0xff, + 0x90 & 0xff, + 0x8f & 0xff, + 0x8e & 0xff, + 0x8e & 0xff, + 0x8d & 0xff, + 0x8c & 0xff, + 0x8c & 0xff, + 0x8b & 0xff, + 0x8a & 0xff, + 0x8a & 0xff, + 0x89 & 0xff, + 0x89 & 0xff, + 0x88 & 0xff, + 0x87 & 0xff, + 0x87 & 0xff, + 0x86 & 0xff, + 0x86 & 0xff, + 0x85 & 0xff, + 0x84 & 0xff, + 0x84 & 0xff, + 0x83 & 0xff, + 0x83 & 0xff, + 0x82 & 0xff, + 0x82 & 0xff, + 0x81 & 0xff, + 0x81 & 0xff, + 0x80 & 0xff, + 0xff & 0xff, + 0xfd & 0xff, + 0xfb & 0xff, + 0xf9 & 0xff, + 0xf7 & 0xff, + 0xf6 & 0xff, + 0xf4 & 0xff, + 0xf2 & 0xff, + 0xf1 & 0xff, + 0xef & 0xff, + 0xed & 0xff, + 0xec & 0xff, + 0xea & 0xff, + 0xe9 & 0xff, + 0xe7 & 0xff, + 0xe6 & 0xff, + 0xe4 & 0xff, + 0xe3 & 0xff, + 0xe1 & 0xff, + 0xe0 & 0xff, + 0xdf & 0xff, + 0xdd & 0xff, + 0xdc & 0xff, + 0xdb & 0xff, + 0xda & 0xff, + 0xd8 & 0xff, + 0xd7 & 0xff, + 0xd6 & 0xff, + 0xd5 & 0xff, + 0xd4 & 0xff, + 0xd3 & 0xff, + 0xd2 & 0xff, + 0xd0 & 0xff, + 0xcf & 0xff, + 0xce & 0xff, + 0xcd & 0xff, + 0xcc & 0xff, + 0xcb & 0xff, + 0xca & 0xff, + 0xc9 & 0xff, + 0xc8 & 0xff, + 0xc7 & 0xff, + 0xc6 & 0xff, + 0xc6 & 0xff, + 0xc5 & 0xff, + 0xc4 & 0xff, + 0xc3 & 0xff, + 0xc2 & 0xff, + 0xc1 & 0xff, + 0xc0 & 0xff, + 0xbf & 0xff, + 0xbf & 0xff, + 0xbe & 0xff, + 0xbd & 0xff, + 0xbc & 0xff, + 0xbb & 0xff, + 0xbb & 0xff, + 0xba & 0xff, + 0xb9 & 0xff, + 0xb8 & 0xff, + 0xb8 & 0xff, + 0xb7 & 0xff, + 0xb6 & 0xff, + 0xb5 & 0xff, + 0 +}; + +/* constant table RECIP_Data10_2 */ +static const unsigned CONST_TBL_RECIP_Data10_2_0[] = { + 0x3fc & 0x3ff, + 0x3f4 & 0x3ff, + 0x3ec & 0x3ff, + 0x3e5 & 0x3ff, + 0x3dd & 0x3ff, + 0x3d6 & 0x3ff, + 0x3cf & 0x3ff, + 0x3c7 & 0x3ff, + 0x3c0 & 0x3ff, + 0x3b9 & 0x3ff, + 0x3b2 & 0x3ff, + 0x3ac & 0x3ff, + 0x3a5 & 0x3ff, + 0x39e & 0x3ff, + 0x398 & 0x3ff, + 0x391 & 0x3ff, + 0x38b & 0x3ff, + 0x385 & 0x3ff, + 0x37f & 0x3ff, + 0x378 & 0x3ff, + 0x373 & 0x3ff, + 0x36c & 0x3ff, + 0x367 & 0x3ff, + 0x361 & 0x3ff, + 0x35c & 0x3ff, + 0x356 & 0x3ff, + 0x350 & 0x3ff, + 0x34b & 0x3ff, + 0x345 & 0x3ff, + 0x340 & 0x3ff, + 0x33b & 0x3ff, + 0x335 & 0x3ff, + 0x330 & 0x3ff, + 0x32c & 0x3ff, + 0x327 & 0x3ff, + 0x322 & 0x3ff, + 0x31c & 0x3ff, + 0x318 & 0x3ff, + 0x314 & 0x3ff, + 0x30e & 0x3ff, + 0x30a & 0x3ff, + 0x306 & 0x3ff, + 0x300 & 0x3ff, + 0x2fc & 0x3ff, + 0x2f8 & 0x3ff, + 0x2f4 & 0x3ff, + 0x2f0 & 0x3ff, + 0x2ea & 0x3ff, + 0x2e6 & 0x3ff, + 0x2e2 & 0x3ff, + 0x2de & 0x3ff, + 0x2da & 0x3ff, + 0x2d6 & 0x3ff, + 0x2d2 & 0x3ff, + 0x2ce & 0x3ff, + 0x2ca & 0x3ff, + 0x2c6 & 0x3ff, + 0x2c2 & 0x3ff, + 0x2be & 0x3ff, + 0x2ba & 0x3ff, + 0x2b8 & 0x3ff, + 0x2b4 & 0x3ff, + 0x2b0 & 0x3ff, + 0x2ac & 0x3ff, + 0x2a8 & 0x3ff, + 0x2a6 & 0x3ff, + 0x2a2 & 0x3ff, + 0x29e & 0x3ff, + 0x29c & 0x3ff, + 0x298 & 0x3ff, + 0x294 & 0x3ff, + 0x290 & 0x3ff, + 0x28e & 0x3ff, + 0x28a & 0x3ff, + 0x288 & 0x3ff, + 0x284 & 0x3ff, + 0x280 & 0x3ff, + 0x27e & 0x3ff, + 0x27a & 0x3ff, + 0x278 & 0x3ff, + 0x274 & 0x3ff, + 0x272 & 0x3ff, + 0x26e & 0x3ff, + 0x26c & 0x3ff, + 0x268 & 0x3ff, + 0x266 & 0x3ff, + 0x264 & 0x3ff, + 0x260 & 0x3ff, + 0x25e & 0x3ff, + 0x25a & 0x3ff, + 0x258 & 0x3ff, + 0x254 & 0x3ff, + 0x252 & 0x3ff, + 0x250 & 0x3ff, + 0x24c & 0x3ff, + 0x24a & 0x3ff, + 0x248 & 0x3ff, + 0x246 & 0x3ff, + 0x242 & 0x3ff, + 0x240 & 0x3ff, + 0x23e & 0x3ff, + 0x23c & 0x3ff, + 0x238 & 0x3ff, + 0x236 & 0x3ff, + 0x234 & 0x3ff, + 0x232 & 0x3ff, + 0x230 & 0x3ff, + 0x22c & 0x3ff, + 0x22a & 0x3ff, + 0x228 & 0x3ff, + 0x226 & 0x3ff, + 0x224 & 0x3ff, + 0x220 & 0x3ff, + 0x21e & 0x3ff, + 0x21c & 0x3ff, + 0x21a & 0x3ff, + 0x218 & 0x3ff, + 0x216 & 0x3ff, + 0x214 & 0x3ff, + 0x212 & 0x3ff, + 0x210 & 0x3ff, + 0x20e & 0x3ff, + 0x20c & 0x3ff, + 0x208 & 0x3ff, + 0x208 & 0x3ff, + 0x204 & 0x3ff, + 0x204 & 0x3ff, + 0x201 & 0x3ff, + 0 +}; + +/* constant table RSQRT_10b_256 */ +static const unsigned CONST_TBL_RSQRT_10b_256_0[] = { + 0x1a5 & 0x3ff, + 0x1a0 & 0x3ff, + 0x19a & 0x3ff, + 0x195 & 0x3ff, + 0x18f & 0x3ff, + 0x18a & 0x3ff, + 0x185 & 0x3ff, + 0x180 & 0x3ff, + 0x17a & 0x3ff, + 0x175 & 0x3ff, + 0x170 & 0x3ff, + 0x16b & 0x3ff, + 0x166 & 0x3ff, + 0x161 & 0x3ff, + 0x15d & 0x3ff, + 0x158 & 0x3ff, + 0x153 & 0x3ff, + 0x14e & 0x3ff, + 0x14a & 0x3ff, + 0x145 & 0x3ff, + 0x140 & 0x3ff, + 0x13c & 0x3ff, + 0x138 & 0x3ff, + 0x133 & 0x3ff, + 0x12f & 0x3ff, + 0x12a & 0x3ff, + 0x126 & 0x3ff, + 0x122 & 0x3ff, + 0x11e & 0x3ff, + 0x11a & 0x3ff, + 0x115 & 0x3ff, + 0x111 & 0x3ff, + 0x10d & 0x3ff, + 0x109 & 0x3ff, + 0x105 & 0x3ff, + 0x101 & 0x3ff, + 0xfd & 0x3ff, + 0xfa & 0x3ff, + 0xf6 & 0x3ff, + 0xf2 & 0x3ff, + 0xee & 0x3ff, + 0xea & 0x3ff, + 0xe7 & 0x3ff, + 0xe3 & 0x3ff, + 0xdf & 0x3ff, + 0xdc & 0x3ff, + 0xd8 & 0x3ff, + 0xd5 & 0x3ff, + 0xd1 & 0x3ff, + 0xce & 0x3ff, + 0xca & 0x3ff, + 0xc7 & 0x3ff, + 0xc3 & 0x3ff, + 0xc0 & 0x3ff, + 0xbd & 0x3ff, + 0xb9 & 0x3ff, + 0xb6 & 0x3ff, + 0xb3 & 0x3ff, + 0xb0 & 0x3ff, + 0xad & 0x3ff, + 0xa9 & 0x3ff, + 0xa6 & 0x3ff, + 0xa3 & 0x3ff, + 0xa0 & 0x3ff, + 0x9d & 0x3ff, + 0x9a & 0x3ff, + 0x97 & 0x3ff, + 0x94 & 0x3ff, + 0x91 & 0x3ff, + 0x8e & 0x3ff, + 0x8b & 0x3ff, + 0x88 & 0x3ff, + 0x85 & 0x3ff, + 0x82 & 0x3ff, + 0x7f & 0x3ff, + 0x7d & 0x3ff, + 0x7a & 0x3ff, + 0x77 & 0x3ff, + 0x74 & 0x3ff, + 0x71 & 0x3ff, + 0x6f & 0x3ff, + 0x6c & 0x3ff, + 0x69 & 0x3ff, + 0x67 & 0x3ff, + 0x64 & 0x3ff, + 0x61 & 0x3ff, + 0x5f & 0x3ff, + 0x5c & 0x3ff, + 0x5a & 0x3ff, + 0x57 & 0x3ff, + 0x54 & 0x3ff, + 0x52 & 0x3ff, + 0x4f & 0x3ff, + 0x4d & 0x3ff, + 0x4a & 0x3ff, + 0x48 & 0x3ff, + 0x45 & 0x3ff, + 0x43 & 0x3ff, + 0x41 & 0x3ff, + 0x3e & 0x3ff, + 0x3c & 0x3ff, + 0x3a & 0x3ff, + 0x37 & 0x3ff, + 0x35 & 0x3ff, + 0x33 & 0x3ff, + 0x30 & 0x3ff, + 0x2e & 0x3ff, + 0x2c & 0x3ff, + 0x29 & 0x3ff, + 0x27 & 0x3ff, + 0x25 & 0x3ff, + 0x23 & 0x3ff, + 0x20 & 0x3ff, + 0x1e & 0x3ff, + 0x1c & 0x3ff, + 0x1a & 0x3ff, + 0x18 & 0x3ff, + 0x16 & 0x3ff, + 0x14 & 0x3ff, + 0x11 & 0x3ff, + 0xf & 0x3ff, + 0xd & 0x3ff, + 0xb & 0x3ff, + 0x9 & 0x3ff, + 0x7 & 0x3ff, + 0x5 & 0x3ff, + 0x3 & 0x3ff, + 0x1 & 0x3ff, + 0x3fc & 0x3ff, + 0x3f4 & 0x3ff, + 0x3ec & 0x3ff, + 0x3e5 & 0x3ff, + 0x3dd & 0x3ff, + 0x3d5 & 0x3ff, + 0x3ce & 0x3ff, + 0x3c7 & 0x3ff, + 0x3bf & 0x3ff, + 0x3b8 & 0x3ff, + 0x3b1 & 0x3ff, + 0x3aa & 0x3ff, + 0x3a3 & 0x3ff, + 0x39c & 0x3ff, + 0x395 & 0x3ff, + 0x38e & 0x3ff, + 0x388 & 0x3ff, + 0x381 & 0x3ff, + 0x37a & 0x3ff, + 0x374 & 0x3ff, + 0x36d & 0x3ff, + 0x367 & 0x3ff, + 0x361 & 0x3ff, + 0x35a & 0x3ff, + 0x354 & 0x3ff, + 0x34e & 0x3ff, + 0x348 & 0x3ff, + 0x342 & 0x3ff, + 0x33c & 0x3ff, + 0x336 & 0x3ff, + 0x330 & 0x3ff, + 0x32b & 0x3ff, + 0x325 & 0x3ff, + 0x31f & 0x3ff, + 0x31a & 0x3ff, + 0x314 & 0x3ff, + 0x30f & 0x3ff, + 0x309 & 0x3ff, + 0x304 & 0x3ff, + 0x2fe & 0x3ff, + 0x2f9 & 0x3ff, + 0x2f4 & 0x3ff, + 0x2ee & 0x3ff, + 0x2e9 & 0x3ff, + 0x2e4 & 0x3ff, + 0x2df & 0x3ff, + 0x2da & 0x3ff, + 0x2d5 & 0x3ff, + 0x2d0 & 0x3ff, + 0x2cb & 0x3ff, + 0x2c6 & 0x3ff, + 0x2c1 & 0x3ff, + 0x2bd & 0x3ff, + 0x2b8 & 0x3ff, + 0x2b3 & 0x3ff, + 0x2ae & 0x3ff, + 0x2aa & 0x3ff, + 0x2a5 & 0x3ff, + 0x2a1 & 0x3ff, + 0x29c & 0x3ff, + 0x298 & 0x3ff, + 0x293 & 0x3ff, + 0x28f & 0x3ff, + 0x28a & 0x3ff, + 0x286 & 0x3ff, + 0x282 & 0x3ff, + 0x27d & 0x3ff, + 0x279 & 0x3ff, + 0x275 & 0x3ff, + 0x271 & 0x3ff, + 0x26d & 0x3ff, + 0x268 & 0x3ff, + 0x264 & 0x3ff, + 0x260 & 0x3ff, + 0x25c & 0x3ff, + 0x258 & 0x3ff, + 0x254 & 0x3ff, + 0x250 & 0x3ff, + 0x24c & 0x3ff, + 0x249 & 0x3ff, + 0x245 & 0x3ff, + 0x241 & 0x3ff, + 0x23d & 0x3ff, + 0x239 & 0x3ff, + 0x235 & 0x3ff, + 0x232 & 0x3ff, + 0x22e & 0x3ff, + 0x22a & 0x3ff, + 0x227 & 0x3ff, + 0x223 & 0x3ff, + 0x220 & 0x3ff, + 0x21c & 0x3ff, + 0x218 & 0x3ff, + 0x215 & 0x3ff, + 0x211 & 0x3ff, + 0x20e & 0x3ff, + 0x20a & 0x3ff, + 0x207 & 0x3ff, + 0x204 & 0x3ff, + 0x200 & 0x3ff, + 0x1fd & 0x3ff, + 0x1f9 & 0x3ff, + 0x1f6 & 0x3ff, + 0x1f3 & 0x3ff, + 0x1f0 & 0x3ff, + 0x1ec & 0x3ff, + 0x1e9 & 0x3ff, + 0x1e6 & 0x3ff, + 0x1e3 & 0x3ff, + 0x1df & 0x3ff, + 0x1dc & 0x3ff, + 0x1d9 & 0x3ff, + 0x1d6 & 0x3ff, + 0x1d3 & 0x3ff, + 0x1d0 & 0x3ff, + 0x1cd & 0x3ff, + 0x1ca & 0x3ff, + 0x1c7 & 0x3ff, + 0x1c4 & 0x3ff, + 0x1c1 & 0x3ff, + 0x1be & 0x3ff, + 0x1bb & 0x3ff, + 0x1b8 & 0x3ff, + 0x1b5 & 0x3ff, + 0x1b2 & 0x3ff, + 0x1af & 0x3ff, + 0x1ac & 0x3ff, + 0x1aa & 0x3ff, + 0 +}; + +/* constant table RECIP_10b_256 */ +static const unsigned CONST_TBL_RECIP_10b_256_0[] = { + 0x3fc & 0x3ff, + 0x3f4 & 0x3ff, + 0x3ec & 0x3ff, + 0x3e4 & 0x3ff, + 0x3dd & 0x3ff, + 0x3d5 & 0x3ff, + 0x3cd & 0x3ff, + 0x3c6 & 0x3ff, + 0x3be & 0x3ff, + 0x3b7 & 0x3ff, + 0x3af & 0x3ff, + 0x3a8 & 0x3ff, + 0x3a1 & 0x3ff, + 0x399 & 0x3ff, + 0x392 & 0x3ff, + 0x38b & 0x3ff, + 0x384 & 0x3ff, + 0x37d & 0x3ff, + 0x376 & 0x3ff, + 0x36f & 0x3ff, + 0x368 & 0x3ff, + 0x361 & 0x3ff, + 0x35b & 0x3ff, + 0x354 & 0x3ff, + 0x34d & 0x3ff, + 0x346 & 0x3ff, + 0x340 & 0x3ff, + 0x339 & 0x3ff, + 0x333 & 0x3ff, + 0x32c & 0x3ff, + 0x326 & 0x3ff, + 0x320 & 0x3ff, + 0x319 & 0x3ff, + 0x313 & 0x3ff, + 0x30d & 0x3ff, + 0x307 & 0x3ff, + 0x300 & 0x3ff, + 0x2fa & 0x3ff, + 0x2f4 & 0x3ff, + 0x2ee & 0x3ff, + 0x2e8 & 0x3ff, + 0x2e2 & 0x3ff, + 0x2dc & 0x3ff, + 0x2d7 & 0x3ff, + 0x2d1 & 0x3ff, + 0x2cb & 0x3ff, + 0x2c5 & 0x3ff, + 0x2bf & 0x3ff, + 0x2ba & 0x3ff, + 0x2b4 & 0x3ff, + 0x2af & 0x3ff, + 0x2a9 & 0x3ff, + 0x2a3 & 0x3ff, + 0x29e & 0x3ff, + 0x299 & 0x3ff, + 0x293 & 0x3ff, + 0x28e & 0x3ff, + 0x288 & 0x3ff, + 0x283 & 0x3ff, + 0x27e & 0x3ff, + 0x279 & 0x3ff, + 0x273 & 0x3ff, + 0x26e & 0x3ff, + 0x269 & 0x3ff, + 0x264 & 0x3ff, + 0x25f & 0x3ff, + 0x25a & 0x3ff, + 0x255 & 0x3ff, + 0x250 & 0x3ff, + 0x24b & 0x3ff, + 0x246 & 0x3ff, + 0x241 & 0x3ff, + 0x23c & 0x3ff, + 0x237 & 0x3ff, + 0x232 & 0x3ff, + 0x22e & 0x3ff, + 0x229 & 0x3ff, + 0x224 & 0x3ff, + 0x21f & 0x3ff, + 0x21b & 0x3ff, + 0x216 & 0x3ff, + 0x211 & 0x3ff, + 0x20d & 0x3ff, + 0x208 & 0x3ff, + 0x204 & 0x3ff, + 0x1ff & 0x3ff, + 0x1fb & 0x3ff, + 0x1f6 & 0x3ff, + 0x1f2 & 0x3ff, + 0x1ed & 0x3ff, + 0x1e9 & 0x3ff, + 0x1e5 & 0x3ff, + 0x1e0 & 0x3ff, + 0x1dc & 0x3ff, + 0x1d8 & 0x3ff, + 0x1d4 & 0x3ff, + 0x1cf & 0x3ff, + 0x1cb & 0x3ff, + 0x1c7 & 0x3ff, + 0x1c3 & 0x3ff, + 0x1bf & 0x3ff, + 0x1bb & 0x3ff, + 0x1b6 & 0x3ff, + 0x1b2 & 0x3ff, + 0x1ae & 0x3ff, + 0x1aa & 0x3ff, + 0x1a6 & 0x3ff, + 0x1a2 & 0x3ff, + 0x19e & 0x3ff, + 0x19a & 0x3ff, + 0x197 & 0x3ff, + 0x193 & 0x3ff, + 0x18f & 0x3ff, + 0x18b & 0x3ff, + 0x187 & 0x3ff, + 0x183 & 0x3ff, + 0x17f & 0x3ff, + 0x17c & 0x3ff, + 0x178 & 0x3ff, + 0x174 & 0x3ff, + 0x171 & 0x3ff, + 0x16d & 0x3ff, + 0x169 & 0x3ff, + 0x166 & 0x3ff, + 0x162 & 0x3ff, + 0x15e & 0x3ff, + 0x15b & 0x3ff, + 0x157 & 0x3ff, + 0x154 & 0x3ff, + 0x150 & 0x3ff, + 0x14d & 0x3ff, + 0x149 & 0x3ff, + 0x146 & 0x3ff, + 0x142 & 0x3ff, + 0x13f & 0x3ff, + 0x13b & 0x3ff, + 0x138 & 0x3ff, + 0x134 & 0x3ff, + 0x131 & 0x3ff, + 0x12e & 0x3ff, + 0x12a & 0x3ff, + 0x127 & 0x3ff, + 0x124 & 0x3ff, + 0x120 & 0x3ff, + 0x11d & 0x3ff, + 0x11a & 0x3ff, + 0x117 & 0x3ff, + 0x113 & 0x3ff, + 0x110 & 0x3ff, + 0x10d & 0x3ff, + 0x10a & 0x3ff, + 0x107 & 0x3ff, + 0x103 & 0x3ff, + 0x100 & 0x3ff, + 0xfd & 0x3ff, + 0xfa & 0x3ff, + 0xf7 & 0x3ff, + 0xf4 & 0x3ff, + 0xf1 & 0x3ff, + 0xee & 0x3ff, + 0xeb & 0x3ff, + 0xe8 & 0x3ff, + 0xe5 & 0x3ff, + 0xe2 & 0x3ff, + 0xdf & 0x3ff, + 0xdc & 0x3ff, + 0xd9 & 0x3ff, + 0xd6 & 0x3ff, + 0xd3 & 0x3ff, + 0xd0 & 0x3ff, + 0xcd & 0x3ff, + 0xca & 0x3ff, + 0xc8 & 0x3ff, + 0xc5 & 0x3ff, + 0xc2 & 0x3ff, + 0xbf & 0x3ff, + 0xbc & 0x3ff, + 0xb9 & 0x3ff, + 0xb7 & 0x3ff, + 0xb4 & 0x3ff, + 0xb1 & 0x3ff, + 0xae & 0x3ff, + 0xac & 0x3ff, + 0xa9 & 0x3ff, + 0xa6 & 0x3ff, + 0xa4 & 0x3ff, + 0xa1 & 0x3ff, + 0x9e & 0x3ff, + 0x9c & 0x3ff, + 0x99 & 0x3ff, + 0x96 & 0x3ff, + 0x94 & 0x3ff, + 0x91 & 0x3ff, + 0x8e & 0x3ff, + 0x8c & 0x3ff, + 0x89 & 0x3ff, + 0x87 & 0x3ff, + 0x84 & 0x3ff, + 0x82 & 0x3ff, + 0x7f & 0x3ff, + 0x7c & 0x3ff, + 0x7a & 0x3ff, + 0x77 & 0x3ff, + 0x75 & 0x3ff, + 0x73 & 0x3ff, + 0x70 & 0x3ff, + 0x6e & 0x3ff, + 0x6b & 0x3ff, + 0x69 & 0x3ff, + 0x66 & 0x3ff, + 0x64 & 0x3ff, + 0x61 & 0x3ff, + 0x5f & 0x3ff, + 0x5d & 0x3ff, + 0x5a & 0x3ff, + 0x58 & 0x3ff, + 0x56 & 0x3ff, + 0x53 & 0x3ff, + 0x51 & 0x3ff, + 0x4f & 0x3ff, + 0x4c & 0x3ff, + 0x4a & 0x3ff, + 0x48 & 0x3ff, + 0x45 & 0x3ff, + 0x43 & 0x3ff, + 0x41 & 0x3ff, + 0x3f & 0x3ff, + 0x3c & 0x3ff, + 0x3a & 0x3ff, + 0x38 & 0x3ff, + 0x36 & 0x3ff, + 0x33 & 0x3ff, + 0x31 & 0x3ff, + 0x2f & 0x3ff, + 0x2d & 0x3ff, + 0x2b & 0x3ff, + 0x29 & 0x3ff, + 0x26 & 0x3ff, + 0x24 & 0x3ff, + 0x22 & 0x3ff, + 0x20 & 0x3ff, + 0x1e & 0x3ff, + 0x1c & 0x3ff, + 0x1a & 0x3ff, + 0x18 & 0x3ff, + 0x15 & 0x3ff, + 0x13 & 0x3ff, + 0x11 & 0x3ff, + 0xf & 0x3ff, + 0xd & 0x3ff, + 0xb & 0x3ff, + 0x9 & 0x3ff, + 0x7 & 0x3ff, + 0x5 & 0x3ff, + 0x3 & 0x3ff, + 0x1 & 0x3ff, + 0 +}; + + +/* Instruction operands. */ + +static int +OperandSem_opnd_sem_MR_0_decode (uint32 *valp) +{ + *valp += 2; + return 0; +} + +static int +OperandSem_opnd_sem_MR_0_encode (uint32 *valp) +{ + int error; + error = ((*valp & ~0x3) != 0) || ((*valp & 0x2) == 0); + *valp = *valp & 1; + return error; +} + +static int +OperandSem_opnd_sem_soffsetx4_decode (uint32 *valp) +{ + unsigned soffsetx4_out_0; + unsigned soffsetx4_in_0; + soffsetx4_in_0 = *valp & 0x3ffff; + soffsetx4_out_0 = 0x4 + ((((int) soffsetx4_in_0 << 14) >> 14) << 2); + *valp = soffsetx4_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_soffsetx4_encode (uint32 *valp) +{ + unsigned soffsetx4_in_0; + unsigned soffsetx4_out_0; + soffsetx4_out_0 = *valp; + soffsetx4_in_0 = ((soffsetx4_out_0 - 0x4) >> 2) & 0x3ffff; + *valp = soffsetx4_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_uimm12x8_decode (uint32 *valp) +{ + unsigned uimm12x8_out_0; + unsigned uimm12x8_in_0; + uimm12x8_in_0 = *valp & 0xfff; + uimm12x8_out_0 = uimm12x8_in_0 << 3; + *valp = uimm12x8_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_uimm12x8_encode (uint32 *valp) +{ + unsigned uimm12x8_in_0; + unsigned uimm12x8_out_0; + uimm12x8_out_0 = *valp; + uimm12x8_in_0 = ((uimm12x8_out_0 >> 3) & 0xfff); + *valp = uimm12x8_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_simm4_decode (uint32 *valp) +{ + unsigned simm4_out_0; + unsigned simm4_in_0; + simm4_in_0 = *valp & 0xf; + simm4_out_0 = ((int) simm4_in_0 << 28) >> 28; + *valp = simm4_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_simm4_encode (uint32 *valp) +{ + unsigned simm4_in_0; + unsigned simm4_out_0; + simm4_out_0 = *valp; + simm4_in_0 = (simm4_out_0 & 0xf); + *valp = simm4_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_AR_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +OperandSem_opnd_sem_AR_encode (uint32 *valp) +{ + int error; + error = (*valp >= 64); + return error; +} + +static int +OperandSem_opnd_sem_AR_0_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +OperandSem_opnd_sem_AR_0_encode (uint32 *valp) +{ + int error; + error = (*valp >= 64); + return error; +} + +static int +OperandSem_opnd_sem_AR_1_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +OperandSem_opnd_sem_AR_1_encode (uint32 *valp) +{ + int error; + error = (*valp >= 64); + return error; +} + +static int +OperandSem_opnd_sem_AR_2_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +OperandSem_opnd_sem_AR_2_encode (uint32 *valp) +{ + int error; + error = (*valp >= 64); + return error; +} + +static int +OperandSem_opnd_sem_AR_3_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +OperandSem_opnd_sem_AR_3_encode (uint32 *valp) +{ + int error; + error = (*valp >= 64); + return error; +} + +static int +OperandSem_opnd_sem_AR_4_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +OperandSem_opnd_sem_AR_4_encode (uint32 *valp) +{ + int error; + error = (*valp >= 64); + return error; +} + +static int +OperandSem_opnd_sem_immrx4_decode (uint32 *valp) +{ + unsigned immrx4_out_0; + unsigned immrx4_in_0; + immrx4_in_0 = *valp & 0xf; + immrx4_out_0 = (((0xfffffff) << 4) | immrx4_in_0) << 2; + *valp = immrx4_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_immrx4_encode (uint32 *valp) +{ + unsigned immrx4_in_0; + unsigned immrx4_out_0; + immrx4_out_0 = *valp; + immrx4_in_0 = ((immrx4_out_0 >> 2) & 0xf); + *valp = immrx4_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_lsi4x4_decode (uint32 *valp) +{ + unsigned lsi4x4_out_0; + unsigned lsi4x4_in_0; + lsi4x4_in_0 = *valp & 0xf; + lsi4x4_out_0 = lsi4x4_in_0 << 2; + *valp = lsi4x4_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_lsi4x4_encode (uint32 *valp) +{ + unsigned lsi4x4_in_0; + unsigned lsi4x4_out_0; + lsi4x4_out_0 = *valp; + lsi4x4_in_0 = ((lsi4x4_out_0 >> 2) & 0xf); + *valp = lsi4x4_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_simm7_decode (uint32 *valp) +{ + unsigned simm7_out_0; + unsigned simm7_in_0; + simm7_in_0 = *valp & 0x7f; + simm7_out_0 = ((((-((((simm7_in_0 >> 6) & 1)) & (((simm7_in_0 >> 5) & 1)))) & 0x1ffffff)) << 7) | simm7_in_0; + *valp = simm7_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_simm7_encode (uint32 *valp) +{ + unsigned simm7_in_0; + unsigned simm7_out_0; + simm7_out_0 = *valp; + simm7_in_0 = (simm7_out_0 & 0x7f); + *valp = simm7_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_uimm6_decode (uint32 *valp) +{ + unsigned uimm6_out_0; + unsigned uimm6_in_0; + uimm6_in_0 = *valp & 0x3f; + uimm6_out_0 = 0x4 + (((0) << 6) | uimm6_in_0); + *valp = uimm6_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_uimm6_encode (uint32 *valp) +{ + unsigned uimm6_in_0; + unsigned uimm6_out_0; + uimm6_out_0 = *valp; + uimm6_in_0 = (uimm6_out_0 - 0x4) & 0x3f; + *valp = uimm6_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_ai4const_decode (uint32 *valp) +{ + unsigned ai4const_out_0; + unsigned ai4const_in_0; + ai4const_in_0 = *valp & 0xf; + ai4const_out_0 = CONST_TBL_ai4c_0[ai4const_in_0 & 0xf]; + *valp = ai4const_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_ai4const_encode (uint32 *valp) +{ + unsigned ai4const_in_0; + unsigned ai4const_out_0; + ai4const_out_0 = *valp; + switch (ai4const_out_0) + { + case 0xffffffff: ai4const_in_0 = 0; break; + case 0x1: ai4const_in_0 = 0x1; break; + case 0x2: ai4const_in_0 = 0x2; break; + case 0x3: ai4const_in_0 = 0x3; break; + case 0x4: ai4const_in_0 = 0x4; break; + case 0x5: ai4const_in_0 = 0x5; break; + case 0x6: ai4const_in_0 = 0x6; break; + case 0x7: ai4const_in_0 = 0x7; break; + case 0x8: ai4const_in_0 = 0x8; break; + case 0x9: ai4const_in_0 = 0x9; break; + case 0xa: ai4const_in_0 = 0xa; break; + case 0xb: ai4const_in_0 = 0xb; break; + case 0xc: ai4const_in_0 = 0xc; break; + case 0xd: ai4const_in_0 = 0xd; break; + case 0xe: ai4const_in_0 = 0xe; break; + default: ai4const_in_0 = 0xf; break; + } + *valp = ai4const_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_b4const_decode (uint32 *valp) +{ + unsigned b4const_out_0; + unsigned b4const_in_0; + b4const_in_0 = *valp & 0xf; + b4const_out_0 = CONST_TBL_b4c_0[b4const_in_0 & 0xf]; + *valp = b4const_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_b4const_encode (uint32 *valp) +{ + unsigned b4const_in_0; + unsigned b4const_out_0; + b4const_out_0 = *valp; + switch (b4const_out_0) + { + case 0xffffffff: b4const_in_0 = 0; break; + case 0x1: b4const_in_0 = 0x1; break; + case 0x2: b4const_in_0 = 0x2; break; + case 0x3: b4const_in_0 = 0x3; break; + case 0x4: b4const_in_0 = 0x4; break; + case 0x5: b4const_in_0 = 0x5; break; + case 0x6: b4const_in_0 = 0x6; break; + case 0x7: b4const_in_0 = 0x7; break; + case 0x8: b4const_in_0 = 0x8; break; + case 0xa: b4const_in_0 = 0x9; break; + case 0xc: b4const_in_0 = 0xa; break; + case 0x10: b4const_in_0 = 0xb; break; + case 0x20: b4const_in_0 = 0xc; break; + case 0x40: b4const_in_0 = 0xd; break; + case 0x80: b4const_in_0 = 0xe; break; + default: b4const_in_0 = 0xf; break; + } + *valp = b4const_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_b4constu_decode (uint32 *valp) +{ + unsigned b4constu_out_0; + unsigned b4constu_in_0; + b4constu_in_0 = *valp & 0xf; + b4constu_out_0 = CONST_TBL_b4cu_0[b4constu_in_0 & 0xf]; + *valp = b4constu_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_b4constu_encode (uint32 *valp) +{ + unsigned b4constu_in_0; + unsigned b4constu_out_0; + b4constu_out_0 = *valp; + switch (b4constu_out_0) + { + case 0x8000: b4constu_in_0 = 0; break; + case 0x10000: b4constu_in_0 = 0x1; break; + case 0x2: b4constu_in_0 = 0x2; break; + case 0x3: b4constu_in_0 = 0x3; break; + case 0x4: b4constu_in_0 = 0x4; break; + case 0x5: b4constu_in_0 = 0x5; break; + case 0x6: b4constu_in_0 = 0x6; break; + case 0x7: b4constu_in_0 = 0x7; break; + case 0x8: b4constu_in_0 = 0x8; break; + case 0xa: b4constu_in_0 = 0x9; break; + case 0xc: b4constu_in_0 = 0xa; break; + case 0x10: b4constu_in_0 = 0xb; break; + case 0x20: b4constu_in_0 = 0xc; break; + case 0x40: b4constu_in_0 = 0xd; break; + case 0x80: b4constu_in_0 = 0xe; break; + default: b4constu_in_0 = 0xf; break; + } + *valp = b4constu_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_uimm8_decode (uint32 *valp) +{ + unsigned uimm8_out_0; + unsigned uimm8_in_0; + uimm8_in_0 = *valp & 0xff; + uimm8_out_0 = uimm8_in_0; + *valp = uimm8_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_uimm8_encode (uint32 *valp) +{ + unsigned uimm8_in_0; + unsigned uimm8_out_0; + uimm8_out_0 = *valp; + uimm8_in_0 = (uimm8_out_0 & 0xff); + *valp = uimm8_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_uimm8x2_decode (uint32 *valp) +{ + unsigned uimm8x2_out_0; + unsigned uimm8x2_in_0; + uimm8x2_in_0 = *valp & 0xff; + uimm8x2_out_0 = uimm8x2_in_0 << 1; + *valp = uimm8x2_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_uimm8x2_encode (uint32 *valp) +{ + unsigned uimm8x2_in_0; + unsigned uimm8x2_out_0; + uimm8x2_out_0 = *valp; + uimm8x2_in_0 = ((uimm8x2_out_0 >> 1) & 0xff); + *valp = uimm8x2_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_uimm8x4_decode (uint32 *valp) +{ + unsigned uimm8x4_out_0; + unsigned uimm8x4_in_0; + uimm8x4_in_0 = *valp & 0xff; + uimm8x4_out_0 = uimm8x4_in_0 << 2; + *valp = uimm8x4_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_uimm8x4_encode (uint32 *valp) +{ + unsigned uimm8x4_in_0; + unsigned uimm8x4_out_0; + uimm8x4_out_0 = *valp; + uimm8x4_in_0 = ((uimm8x4_out_0 >> 2) & 0xff); + *valp = uimm8x4_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_uimm4x16_decode (uint32 *valp) +{ + unsigned uimm4x16_out_0; + unsigned uimm4x16_in_0; + uimm4x16_in_0 = *valp & 0xf; + uimm4x16_out_0 = uimm4x16_in_0 << 4; + *valp = uimm4x16_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_uimm4x16_encode (uint32 *valp) +{ + unsigned uimm4x16_in_0; + unsigned uimm4x16_out_0; + uimm4x16_out_0 = *valp; + uimm4x16_in_0 = ((uimm4x16_out_0 >> 4) & 0xf); + *valp = uimm4x16_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_simm8_decode (uint32 *valp) +{ + unsigned simm8_out_0; + unsigned simm8_in_0; + simm8_in_0 = *valp & 0xff; + simm8_out_0 = ((int) simm8_in_0 << 24) >> 24; + *valp = simm8_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_simm8_encode (uint32 *valp) +{ + unsigned simm8_in_0; + unsigned simm8_out_0; + simm8_out_0 = *valp; + simm8_in_0 = (simm8_out_0 & 0xff); + *valp = simm8_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_simm8x256_decode (uint32 *valp) +{ + unsigned simm8x256_out_0; + unsigned simm8x256_in_0; + simm8x256_in_0 = *valp & 0xff; + simm8x256_out_0 = (((int) simm8x256_in_0 << 24) >> 24) << 8; + *valp = simm8x256_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_simm8x256_encode (uint32 *valp) +{ + unsigned simm8x256_in_0; + unsigned simm8x256_out_0; + simm8x256_out_0 = *valp; + simm8x256_in_0 = ((simm8x256_out_0 >> 8) & 0xff); + *valp = simm8x256_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_simm12b_decode (uint32 *valp) +{ + unsigned simm12b_out_0; + unsigned simm12b_in_0; + simm12b_in_0 = *valp & 0xfff; + simm12b_out_0 = ((int) simm12b_in_0 << 20) >> 20; + *valp = simm12b_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_simm12b_encode (uint32 *valp) +{ + unsigned simm12b_in_0; + unsigned simm12b_out_0; + simm12b_out_0 = *valp; + simm12b_in_0 = (simm12b_out_0 & 0xfff); + *valp = simm12b_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_msalp32_decode (uint32 *valp) +{ + unsigned msalp32_out_0; + unsigned msalp32_in_0; + msalp32_in_0 = *valp & 0x1f; + msalp32_out_0 = 0x20 - msalp32_in_0; + *valp = msalp32_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_msalp32_encode (uint32 *valp) +{ + unsigned msalp32_in_0; + unsigned msalp32_out_0; + msalp32_out_0 = *valp; + msalp32_in_0 = (0x20 - msalp32_out_0) & 0x1f; + *valp = msalp32_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_op2p1_decode (uint32 *valp) +{ + unsigned op2p1_out_0; + unsigned op2p1_in_0; + op2p1_in_0 = *valp & 0xf; + op2p1_out_0 = op2p1_in_0 + 0x1; + *valp = op2p1_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_op2p1_encode (uint32 *valp) +{ + unsigned op2p1_in_0; + unsigned op2p1_out_0; + op2p1_out_0 = *valp; + op2p1_in_0 = (op2p1_out_0 - 0x1) & 0xf; + *valp = op2p1_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_label8_decode (uint32 *valp) +{ + unsigned label8_out_0; + unsigned label8_in_0; + label8_in_0 = *valp & 0xff; + label8_out_0 = 0x4 + (((int) label8_in_0 << 24) >> 24); + *valp = label8_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_label8_encode (uint32 *valp) +{ + unsigned label8_in_0; + unsigned label8_out_0; + label8_out_0 = *valp; + label8_in_0 = (label8_out_0 - 0x4) & 0xff; + *valp = label8_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_ulabel8_decode (uint32 *valp) +{ + unsigned ulabel8_out_0; + unsigned ulabel8_in_0; + ulabel8_in_0 = *valp & 0xff; + ulabel8_out_0 = 0x4 + (((0) << 8) | ulabel8_in_0); + *valp = ulabel8_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_ulabel8_encode (uint32 *valp) +{ + unsigned ulabel8_in_0; + unsigned ulabel8_out_0; + ulabel8_out_0 = *valp; + ulabel8_in_0 = (ulabel8_out_0 - 0x4) & 0xff; + *valp = ulabel8_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_label12_decode (uint32 *valp) +{ + unsigned label12_out_0; + unsigned label12_in_0; + label12_in_0 = *valp & 0xfff; + label12_out_0 = 0x4 + (((int) label12_in_0 << 20) >> 20); + *valp = label12_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_label12_encode (uint32 *valp) +{ + unsigned label12_in_0; + unsigned label12_out_0; + label12_out_0 = *valp; + label12_in_0 = (label12_out_0 - 0x4) & 0xfff; + *valp = label12_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_soffset_decode (uint32 *valp) +{ + unsigned soffset_out_0; + unsigned soffset_in_0; + soffset_in_0 = *valp & 0x3ffff; + soffset_out_0 = 0x4 + (((int) soffset_in_0 << 14) >> 14); + *valp = soffset_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_soffset_encode (uint32 *valp) +{ + unsigned soffset_in_0; + unsigned soffset_out_0; + soffset_out_0 = *valp; + soffset_in_0 = (soffset_out_0 - 0x4) & 0x3ffff; + *valp = soffset_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_uimm16x4_decode (uint32 *valp) +{ + unsigned uimm16x4_out_0; + unsigned uimm16x4_in_0; + uimm16x4_in_0 = *valp & 0xffff; + uimm16x4_out_0 = (((0xffff) << 16) | uimm16x4_in_0) << 2; + *valp = uimm16x4_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_uimm16x4_encode (uint32 *valp) +{ + unsigned uimm16x4_in_0; + unsigned uimm16x4_out_0; + uimm16x4_out_0 = *valp; + uimm16x4_in_0 = (uimm16x4_out_0 >> 2) & 0xffff; + *valp = uimm16x4_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_bbi_decode (uint32 *valp) +{ + unsigned bbi_out_0; + unsigned bbi_in_0; + bbi_in_0 = *valp & 0x1f; + bbi_out_0 = (0 << 5) | bbi_in_0; + *valp = bbi_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_bbi_encode (uint32 *valp) +{ + unsigned bbi_in_0; + unsigned bbi_out_0; + bbi_out_0 = *valp; + bbi_in_0 = (bbi_out_0 & 0x1f); + *valp = bbi_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_s_decode (uint32 *valp) +{ + unsigned s_out_0; + unsigned s_in_0; + s_in_0 = *valp & 0xf; + s_out_0 = (0 << 4) | s_in_0; + *valp = s_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_s_encode (uint32 *valp) +{ + unsigned s_in_0; + unsigned s_out_0; + s_out_0 = *valp; + s_in_0 = (s_out_0 & 0xf); + *valp = s_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_MR_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +OperandSem_opnd_sem_MR_encode (uint32 *valp) +{ + int error; + error = (*valp >= 4); + return error; +} + +static int +OperandSem_opnd_sem_MR_1_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +OperandSem_opnd_sem_MR_1_encode (uint32 *valp) +{ + int error; + error = (*valp >= 4); + return error; +} + +static int +OperandSem_opnd_sem_MR_2_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +OperandSem_opnd_sem_MR_2_encode (uint32 *valp) +{ + int error; + error = (*valp >= 4); + return error; +} + +static int +OperandSem_opnd_sem_MR_3_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +OperandSem_opnd_sem_MR_3_encode (uint32 *valp) +{ + int error; + error = (*valp >= 4); + return error; +} + +static int +OperandSem_opnd_sem_MR_4_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +OperandSem_opnd_sem_MR_4_encode (uint32 *valp) +{ + int error; + error = (*valp >= 4); + return error; +} + +static int +OperandSem_opnd_sem_MR_5_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +OperandSem_opnd_sem_MR_5_encode (uint32 *valp) +{ + int error; + error = (*valp >= 4); + return error; +} + +static int +OperandSem_opnd_sem_immt_decode (uint32 *valp) +{ + unsigned immt_out_0; + unsigned immt_in_0; + immt_in_0 = *valp & 0xf; + immt_out_0 = immt_in_0; + *valp = immt_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_immt_encode (uint32 *valp) +{ + unsigned immt_in_0; + unsigned immt_out_0; + immt_out_0 = *valp; + immt_in_0 = immt_out_0 & 0xf; + *valp = immt_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_BR_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +OperandSem_opnd_sem_BR_encode (uint32 *valp) +{ + int error; + error = (*valp >= 16); + return error; +} + +static int +OperandSem_opnd_sem_BR2_decode (uint32 *valp) +{ + *valp = *valp << 1; + return 0; +} + +static int +OperandSem_opnd_sem_BR2_encode (uint32 *valp) +{ + int error; + error = (*valp >= 16) || ((*valp & 1) != 0); + *valp = *valp >> 1; + return error; +} + +static int +OperandSem_opnd_sem_BR4_decode (uint32 *valp) +{ + *valp = *valp << 2; + return 0; +} + +static int +OperandSem_opnd_sem_BR4_encode (uint32 *valp) +{ + int error; + error = (*valp >= 16) || ((*valp & 3) != 0); + *valp = *valp >> 2; + return error; +} + +static int +OperandSem_opnd_sem_BR8_decode (uint32 *valp) +{ + *valp = *valp << 3; + return 0; +} + +static int +OperandSem_opnd_sem_BR8_encode (uint32 *valp) +{ + int error; + error = (*valp >= 16) || ((*valp & 7) != 0); + *valp = *valp >> 3; + return error; +} + +static int +OperandSem_opnd_sem_BR16_decode (uint32 *valp) +{ + *valp = *valp << 4; + return 0; +} + +static int +OperandSem_opnd_sem_BR16_encode (uint32 *valp) +{ + int error; + error = (*valp >= 16) || ((*valp & 15) != 0); + *valp = *valp >> 4; + return error; +} + +static int +OperandSem_opnd_sem_tp7_decode (uint32 *valp) +{ + unsigned tp7_out_0; + unsigned tp7_in_0; + tp7_in_0 = *valp & 0xf; + tp7_out_0 = tp7_in_0 + 0x7; + *valp = tp7_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_tp7_encode (uint32 *valp) +{ + unsigned tp7_in_0; + unsigned tp7_out_0; + tp7_out_0 = *valp; + tp7_in_0 = (tp7_out_0 - 0x7) & 0xf; + *valp = tp7_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_xt_wbr15_label_decode (uint32 *valp) +{ + unsigned xt_wbr15_label_out_0; + unsigned xt_wbr15_label_in_0; + xt_wbr15_label_in_0 = *valp & 0x7fff; + xt_wbr15_label_out_0 = 0x4 + (((int) xt_wbr15_label_in_0 << 17) >> 17); + *valp = xt_wbr15_label_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_xt_wbr15_label_encode (uint32 *valp) +{ + unsigned xt_wbr15_label_in_0; + unsigned xt_wbr15_label_out_0; + xt_wbr15_label_out_0 = *valp; + xt_wbr15_label_in_0 = (xt_wbr15_label_out_0 - 0x4) & 0x7fff; + *valp = xt_wbr15_label_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_dfp_fld_op2_2_decode (uint32 *valp) +{ + unsigned dfp_fld_op2_2_out_0; + unsigned dfp_fld_op2_2_in_0; + dfp_fld_op2_2_in_0 = *valp & 0x1; + dfp_fld_op2_2_out_0 = (0 << 1) | dfp_fld_op2_2_in_0; + *valp = dfp_fld_op2_2_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_dfp_fld_op2_2_encode (uint32 *valp) +{ + unsigned dfp_fld_op2_2_in_0; + unsigned dfp_fld_op2_2_out_0; + dfp_fld_op2_2_out_0 = *valp; + dfp_fld_op2_2_in_0 = (((dfp_fld_op2_2_out_0 >> 0) & 1)) & 0x1; + *valp = dfp_fld_op2_2_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_dfp_fld_op2_1_0_decode (uint32 *valp) +{ + unsigned dfp_fld_op2_1_0_out_0; + unsigned dfp_fld_op2_1_0_in_0; + dfp_fld_op2_1_0_in_0 = *valp & 0x3; + dfp_fld_op2_1_0_out_0 = (0 << 2) | dfp_fld_op2_1_0_in_0; + *valp = dfp_fld_op2_1_0_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_dfp_fld_op2_1_0_encode (uint32 *valp) +{ + unsigned dfp_fld_op2_1_0_in_0; + unsigned dfp_fld_op2_1_0_out_0; + dfp_fld_op2_1_0_out_0 = *valp; + dfp_fld_op2_1_0_in_0 = (dfp_fld_op2_1_0_out_0 & 0x3); + *valp = dfp_fld_op2_1_0_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_FR_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +OperandSem_opnd_sem_FR_encode (uint32 *valp) +{ + int error; + error = (*valp >= 16); + return error; +} + +static int +OperandSem_opnd_sem_imm8x4_decode (uint32 *valp) +{ + unsigned imm8x4_out_0; + unsigned imm8x4_in_0; + imm8x4_in_0 = *valp & 0xff; + imm8x4_out_0 = (0 << 10) | (imm8x4_in_0 << 2) | 0; + *valp = imm8x4_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_imm8x4_encode (uint32 *valp) +{ + unsigned imm8x4_in_0; + unsigned imm8x4_out_0; + imm8x4_out_0 = *valp; + imm8x4_in_0 = ((imm8x4_out_0 >> 2) & 0xff); + *valp = imm8x4_in_0; + return 0; +} + +static int +OperandSem_opnd_sem_imm8x8_decode (uint32 *valp) +{ + unsigned imm8x8_out_0; + unsigned imm8x8_in_0; + imm8x8_in_0 = *valp & 0xff; + imm8x8_out_0 = (0 << 11) | (imm8x8_in_0 << 3) | 0; + *valp = imm8x8_out_0; + return 0; +} + +static int +OperandSem_opnd_sem_imm8x8_encode (uint32 *valp) +{ + unsigned imm8x8_in_0; + unsigned imm8x8_out_0; + imm8x8_out_0 = *valp; + imm8x8_in_0 = ((imm8x8_out_0 >> 3) & 0xff); + *valp = imm8x8_in_0; + return 0; +} + +static int +Operand_soffsetx4_ator (uint32 *valp, uint32 pc) +{ + *valp -= (pc & ~0x3); + return 0; +} + +static int +Operand_soffsetx4_rtoa (uint32 *valp, uint32 pc) +{ + *valp += (pc & ~0x3); + return 0; +} + +static int +Operand_uimm6_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_uimm6_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_label8_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_label8_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_ulabel8_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_ulabel8_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_label12_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_label12_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_soffset_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_soffset_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_uimm16x4_ator (uint32 *valp, uint32 pc) +{ + *valp -= ((pc + 3) & ~0x3); + return 0; +} + +static int +Operand_uimm16x4_rtoa (uint32 *valp, uint32 pc) +{ + *valp += ((pc + 3) & ~0x3); + return 0; +} + +static int +Operand_xt_wbr15_label_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_xt_wbr15_label_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_xt_wbr18_label_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_xt_wbr18_label_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static xtensa_operand_internal operands[] = { + { "soffsetx4", FIELD_offset, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + OperandSem_opnd_sem_soffsetx4_encode, OperandSem_opnd_sem_soffsetx4_decode, + Operand_soffsetx4_ator, Operand_soffsetx4_rtoa }, + { "uimm12x8", FIELD_imm12, -1, 0, + 0, + OperandSem_opnd_sem_uimm12x8_encode, OperandSem_opnd_sem_uimm12x8_decode, + 0, 0 }, + { "simm4", FIELD_mn, -1, 0, + 0, + OperandSem_opnd_sem_simm4_encode, OperandSem_opnd_sem_simm4_decode, + 0, 0 }, + { "arr", FIELD_r, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_AR_encode, OperandSem_opnd_sem_AR_decode, + 0, 0 }, + { "ars", FIELD_s, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_AR_encode, OperandSem_opnd_sem_AR_decode, + 0, 0 }, + { "*ars_invisible", FIELD_s, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + OperandSem_opnd_sem_AR_encode, OperandSem_opnd_sem_AR_decode, + 0, 0 }, + { "art", FIELD_t, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_AR_encode, OperandSem_opnd_sem_AR_decode, + 0, 0 }, + { "ar0", FIELD__ar0, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + OperandSem_opnd_sem_AR_0_encode, OperandSem_opnd_sem_AR_0_decode, + 0, 0 }, + { "ar4", FIELD__ar4, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + OperandSem_opnd_sem_AR_1_encode, OperandSem_opnd_sem_AR_1_decode, + 0, 0 }, + { "ar8", FIELD__ar8, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + OperandSem_opnd_sem_AR_2_encode, OperandSem_opnd_sem_AR_2_decode, + 0, 0 }, + { "ar12", FIELD__ar12, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + OperandSem_opnd_sem_AR_3_encode, OperandSem_opnd_sem_AR_3_decode, + 0, 0 }, + { "ars_entry", FIELD_s, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_AR_4_encode, OperandSem_opnd_sem_AR_4_decode, + 0, 0 }, + { "immrx4", FIELD_r, -1, 0, + 0, + OperandSem_opnd_sem_immrx4_encode, OperandSem_opnd_sem_immrx4_decode, + 0, 0 }, + { "lsi4x4", FIELD_r, -1, 0, + 0, + OperandSem_opnd_sem_lsi4x4_encode, OperandSem_opnd_sem_lsi4x4_decode, + 0, 0 }, + { "simm7", FIELD_imm7, -1, 0, + 0, + OperandSem_opnd_sem_simm7_encode, OperandSem_opnd_sem_simm7_decode, + 0, 0 }, + { "uimm6", FIELD_imm6, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + OperandSem_opnd_sem_uimm6_encode, OperandSem_opnd_sem_uimm6_decode, + Operand_uimm6_ator, Operand_uimm6_rtoa }, + { "ai4const", FIELD_t, -1, 0, + 0, + OperandSem_opnd_sem_ai4const_encode, OperandSem_opnd_sem_ai4const_decode, + 0, 0 }, + { "b4const", FIELD_r, -1, 0, + 0, + OperandSem_opnd_sem_b4const_encode, OperandSem_opnd_sem_b4const_decode, + 0, 0 }, + { "b4constu", FIELD_r, -1, 0, + 0, + OperandSem_opnd_sem_b4constu_encode, OperandSem_opnd_sem_b4constu_decode, + 0, 0 }, + { "uimm8", FIELD_imm8, -1, 0, + 0, + OperandSem_opnd_sem_uimm8_encode, OperandSem_opnd_sem_uimm8_decode, + 0, 0 }, + { "uimm8x2", FIELD_imm8, -1, 0, + 0, + OperandSem_opnd_sem_uimm8x2_encode, OperandSem_opnd_sem_uimm8x2_decode, + 0, 0 }, + { "uimm8x4", FIELD_imm8, -1, 0, + 0, + OperandSem_opnd_sem_uimm8x4_encode, OperandSem_opnd_sem_uimm8x4_decode, + 0, 0 }, + { "uimm4x16", FIELD_op2, -1, 0, + 0, + OperandSem_opnd_sem_uimm4x16_encode, OperandSem_opnd_sem_uimm4x16_decode, + 0, 0 }, + { "uimmrx4", FIELD_r, -1, 0, + 0, + OperandSem_opnd_sem_lsi4x4_encode, OperandSem_opnd_sem_lsi4x4_decode, + 0, 0 }, + { "simm8", FIELD_imm8, -1, 0, + 0, + OperandSem_opnd_sem_simm8_encode, OperandSem_opnd_sem_simm8_decode, + 0, 0 }, + { "simm8x256", FIELD_imm8, -1, 0, + 0, + OperandSem_opnd_sem_simm8x256_encode, OperandSem_opnd_sem_simm8x256_decode, + 0, 0 }, + { "simm12b", FIELD_imm12b, -1, 0, + 0, + OperandSem_opnd_sem_simm12b_encode, OperandSem_opnd_sem_simm12b_decode, + 0, 0 }, + { "msalp32", FIELD_sal, -1, 0, + 0, + OperandSem_opnd_sem_msalp32_encode, OperandSem_opnd_sem_msalp32_decode, + 0, 0 }, + { "op2p1", FIELD_op2, -1, 0, + 0, + OperandSem_opnd_sem_op2p1_encode, OperandSem_opnd_sem_op2p1_decode, + 0, 0 }, + { "label8", FIELD_imm8, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + OperandSem_opnd_sem_label8_encode, OperandSem_opnd_sem_label8_decode, + Operand_label8_ator, Operand_label8_rtoa }, + { "ulabel8", FIELD_imm8, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + OperandSem_opnd_sem_ulabel8_encode, OperandSem_opnd_sem_ulabel8_decode, + Operand_ulabel8_ator, Operand_ulabel8_rtoa }, + { "label12", FIELD_imm12, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + OperandSem_opnd_sem_label12_encode, OperandSem_opnd_sem_label12_decode, + Operand_label12_ator, Operand_label12_rtoa }, + { "soffset", FIELD_offset, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + OperandSem_opnd_sem_soffset_encode, OperandSem_opnd_sem_soffset_decode, + Operand_soffset_ator, Operand_soffset_rtoa }, + { "uimm16x4", FIELD_imm16, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + OperandSem_opnd_sem_uimm16x4_encode, OperandSem_opnd_sem_uimm16x4_decode, + Operand_uimm16x4_ator, Operand_uimm16x4_rtoa }, + { "bbi", FIELD_bbi, -1, 0, + 0, + OperandSem_opnd_sem_bbi_encode, OperandSem_opnd_sem_bbi_decode, + 0, 0 }, + { "sae", FIELD_sae, -1, 0, + 0, + OperandSem_opnd_sem_bbi_encode, OperandSem_opnd_sem_bbi_decode, + 0, 0 }, + { "sas", FIELD_sas, -1, 0, + 0, + OperandSem_opnd_sem_bbi_encode, OperandSem_opnd_sem_bbi_decode, + 0, 0 }, + { "sargt", FIELD_sargt, -1, 0, + 0, + OperandSem_opnd_sem_bbi_encode, OperandSem_opnd_sem_bbi_decode, + 0, 0 }, + { "s", FIELD_s, -1, 0, + 0, + OperandSem_opnd_sem_s_encode, OperandSem_opnd_sem_s_decode, + 0, 0 }, + { "mx", FIELD_x, REGFILE_MR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_UNKNOWN, + OperandSem_opnd_sem_MR_encode, OperandSem_opnd_sem_MR_decode, + 0, 0 }, + { "my", FIELD_y, REGFILE_MR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_UNKNOWN, + OperandSem_opnd_sem_MR_0_encode, OperandSem_opnd_sem_MR_0_decode, + 0, 0 }, + { "mw", FIELD_w, REGFILE_MR, 1, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_MR_1_encode, OperandSem_opnd_sem_MR_1_decode, + 0, 0 }, + { "mr0", FIELD__mr0, REGFILE_MR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + OperandSem_opnd_sem_MR_2_encode, OperandSem_opnd_sem_MR_2_decode, + 0, 0 }, + { "mr1", FIELD__mr1, REGFILE_MR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + OperandSem_opnd_sem_MR_3_encode, OperandSem_opnd_sem_MR_3_decode, + 0, 0 }, + { "mr2", FIELD__mr2, REGFILE_MR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + OperandSem_opnd_sem_MR_4_encode, OperandSem_opnd_sem_MR_4_decode, + 0, 0 }, + { "mr3", FIELD__mr3, REGFILE_MR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + OperandSem_opnd_sem_MR_5_encode, OperandSem_opnd_sem_MR_5_decode, + 0, 0 }, + { "immt", FIELD_t, -1, 0, + 0, + OperandSem_opnd_sem_immt_encode, OperandSem_opnd_sem_immt_decode, + 0, 0 }, + { "imms", FIELD_s, -1, 0, + 0, + OperandSem_opnd_sem_immt_encode, OperandSem_opnd_sem_immt_decode, + 0, 0 }, + { "bt", FIELD_t, REGFILE_BR, 1, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR_encode, OperandSem_opnd_sem_BR_decode, + 0, 0 }, + { "bs", FIELD_s, REGFILE_BR, 1, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR_encode, OperandSem_opnd_sem_BR_decode, + 0, 0 }, + { "br", FIELD_r, REGFILE_BR, 1, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR_encode, OperandSem_opnd_sem_BR_decode, + 0, 0 }, + { "bt2", FIELD_t2, REGFILE_BR, 2, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR2_encode, OperandSem_opnd_sem_BR2_decode, + 0, 0 }, + { "bs2", FIELD_s2, REGFILE_BR, 2, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR2_encode, OperandSem_opnd_sem_BR2_decode, + 0, 0 }, + { "br2", FIELD_r2, REGFILE_BR, 2, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR2_encode, OperandSem_opnd_sem_BR2_decode, + 0, 0 }, + { "bt4", FIELD_t4, REGFILE_BR, 4, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR4_encode, OperandSem_opnd_sem_BR4_decode, + 0, 0 }, + { "bs4", FIELD_s4, REGFILE_BR, 4, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR4_encode, OperandSem_opnd_sem_BR4_decode, + 0, 0 }, + { "br4", FIELD_r4, REGFILE_BR, 4, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR4_encode, OperandSem_opnd_sem_BR4_decode, + 0, 0 }, + { "bt8", FIELD_t8, REGFILE_BR, 8, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR8_encode, OperandSem_opnd_sem_BR8_decode, + 0, 0 }, + { "bs8", FIELD_s8, REGFILE_BR, 8, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR8_encode, OperandSem_opnd_sem_BR8_decode, + 0, 0 }, + { "br8", FIELD_r8, REGFILE_BR, 8, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR8_encode, OperandSem_opnd_sem_BR8_decode, + 0, 0 }, + { "bt16", FIELD__bt16, REGFILE_BR, 16, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR16_encode, OperandSem_opnd_sem_BR16_decode, + 0, 0 }, + { "bs16", FIELD__bs16, REGFILE_BR, 16, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR16_encode, OperandSem_opnd_sem_BR16_decode, + 0, 0 }, + { "br16", FIELD__br16, REGFILE_BR, 16, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_BR16_encode, OperandSem_opnd_sem_BR16_decode, + 0, 0 }, + { "brall", FIELD__brall, REGFILE_BR, 16, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + OperandSem_opnd_sem_BR16_encode, OperandSem_opnd_sem_BR16_decode, + 0, 0 }, + { "tp7", FIELD_t, -1, 0, + 0, + OperandSem_opnd_sem_tp7_encode, OperandSem_opnd_sem_tp7_decode, + 0, 0 }, + { "xt_wbr15_label", FIELD_xt_wbr15_imm, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + OperandSem_opnd_sem_xt_wbr15_label_encode, OperandSem_opnd_sem_xt_wbr15_label_decode, + Operand_xt_wbr15_label_ator, Operand_xt_wbr15_label_rtoa }, + { "xt_wbr18_label", FIELD_xt_wbr18_imm, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + OperandSem_opnd_sem_soffset_encode, OperandSem_opnd_sem_soffset_decode, + Operand_xt_wbr18_label_ator, Operand_xt_wbr18_label_rtoa }, + { "dfp_fld_op2_2", FIELD_dfp_fld_op2_2, -1, 0, + 0, + OperandSem_opnd_sem_dfp_fld_op2_2_encode, OperandSem_opnd_sem_dfp_fld_op2_2_decode, + 0, 0 }, + { "dfp_fld_op2_1_0", FIELD_dfp_fld_op2_1_0, -1, 0, + 0, + OperandSem_opnd_sem_dfp_fld_op2_1_0_encode, OperandSem_opnd_sem_dfp_fld_op2_1_0_decode, + 0, 0 }, + { "dfp_fld_r_0", FIELD_dfp_fld_r_0, -1, 0, + 0, + OperandSem_opnd_sem_dfp_fld_op2_2_encode, OperandSem_opnd_sem_dfp_fld_op2_2_decode, + 0, 0 }, + { "dfp_fld_r_2_1", FIELD_dfp_fld_r_2_1, -1, 0, + 0, + OperandSem_opnd_sem_dfp_fld_op2_1_0_encode, OperandSem_opnd_sem_dfp_fld_op2_1_0_decode, + 0, 0 }, + { "dfp_fld_op2", FIELD_dfp_fld_op2, -1, 0, + 0, + OperandSem_opnd_sem_s_encode, OperandSem_opnd_sem_s_decode, + 0, 0 }, + { "dfp_fld_op2_0", FIELD_dfp_fld_op2_0, -1, 0, + 0, + OperandSem_opnd_sem_dfp_fld_op2_2_encode, OperandSem_opnd_sem_dfp_fld_op2_2_decode, + 0, 0 }, + { "dfp_fld_s_0", FIELD_dfp_fld_s_0, -1, 0, + 0, + OperandSem_opnd_sem_dfp_fld_op2_2_encode, OperandSem_opnd_sem_dfp_fld_op2_2_decode, + 0, 0 }, + { "frr", FIELD_r, REGFILE_FR, 1, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_FR_encode, OperandSem_opnd_sem_FR_decode, + 0, 0 }, + { "frs", FIELD_s, REGFILE_FR, 1, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_FR_encode, OperandSem_opnd_sem_FR_decode, + 0, 0 }, + { "frt", FIELD_t, REGFILE_FR, 1, + XTENSA_OPERAND_IS_REGISTER, + OperandSem_opnd_sem_FR_encode, OperandSem_opnd_sem_FR_decode, + 0, 0 }, + { "imm_t", FIELD_t, -1, 0, + 0, + OperandSem_opnd_sem_s_encode, OperandSem_opnd_sem_s_decode, + 0, 0 }, + { "imm_s", FIELD_s, -1, 0, + 0, + OperandSem_opnd_sem_s_encode, OperandSem_opnd_sem_s_decode, + 0, 0 }, + { "imm8x4", FIELD_imm8, -1, 0, + 0, + OperandSem_opnd_sem_imm8x4_encode, OperandSem_opnd_sem_imm8x4_decode, + 0, 0 }, + { "imm8x8", FIELD_imm8, -1, 0, + 0, + OperandSem_opnd_sem_imm8x8_encode, OperandSem_opnd_sem_imm8x8_decode, + 0, 0 }, + { "bitindex", FIELD_bitindex, -1, 0, + 0, + OperandSem_opnd_sem_bbi_encode, OperandSem_opnd_sem_bbi_decode, + 0, 0 }, + { "t", FIELD_t, -1, 0, 0, 0, 0, 0, 0 }, + { "bbi4", FIELD_bbi4, -1, 0, 0, 0, 0, 0, 0 }, + { "imm12", FIELD_imm12, -1, 0, 0, 0, 0, 0, 0 }, + { "imm8", FIELD_imm8, -1, 0, 0, 0, 0, 0, 0 }, + { "imm12b", FIELD_imm12b, -1, 0, 0, 0, 0, 0, 0 }, + { "imm16", FIELD_imm16, -1, 0, 0, 0, 0, 0, 0 }, + { "m", FIELD_m, -1, 0, 0, 0, 0, 0, 0 }, + { "n", FIELD_n, -1, 0, 0, 0, 0, 0, 0 }, + { "offset", FIELD_offset, -1, 0, 0, 0, 0, 0, 0 }, + { "op0", FIELD_op0, -1, 0, 0, 0, 0, 0, 0 }, + { "op1", FIELD_op1, -1, 0, 0, 0, 0, 0, 0 }, + { "op2", FIELD_op2, -1, 0, 0, 0, 0, 0, 0 }, + { "r", FIELD_r, -1, 0, 0, 0, 0, 0, 0 }, + { "sa4", FIELD_sa4, -1, 0, 0, 0, 0, 0, 0 }, + { "sae4", FIELD_sae4, -1, 0, 0, 0, 0, 0, 0 }, + { "sal", FIELD_sal, -1, 0, 0, 0, 0, 0, 0 }, + { "sas4", FIELD_sas4, -1, 0, 0, 0, 0, 0, 0 }, + { "sr", FIELD_sr, -1, 0, 0, 0, 0, 0, 0 }, + { "st", FIELD_st, -1, 0, 0, 0, 0, 0, 0 }, + { "thi3", FIELD_thi3, -1, 0, 0, 0, 0, 0, 0 }, + { "imm4", FIELD_imm4, -1, 0, 0, 0, 0, 0, 0 }, + { "mn", FIELD_mn, -1, 0, 0, 0, 0, 0, 0 }, + { "i", FIELD_i, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6lo", FIELD_imm6lo, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6hi", FIELD_imm6hi, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7lo", FIELD_imm7lo, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7hi", FIELD_imm7hi, -1, 0, 0, 0, 0, 0, 0 }, + { "z", FIELD_z, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6", FIELD_imm6, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7", FIELD_imm7, -1, 0, 0, 0, 0, 0, 0 }, + { "r3", FIELD_r3, -1, 0, 0, 0, 0, 0, 0 }, + { "rbit2", FIELD_rbit2, -1, 0, 0, 0, 0, 0, 0 }, + { "rhi", FIELD_rhi, -1, 0, 0, 0, 0, 0, 0 }, + { "t3", FIELD_t3, -1, 0, 0, 0, 0, 0, 0 }, + { "tbit2", FIELD_tbit2, -1, 0, 0, 0, 0, 0, 0 }, + { "tlo", FIELD_tlo, -1, 0, 0, 0, 0, 0, 0 }, + { "w", FIELD_w, -1, 0, 0, 0, 0, 0, 0 }, + { "y", FIELD_y, -1, 0, 0, 0, 0, 0, 0 }, + { "x", FIELD_x, -1, 0, 0, 0, 0, 0, 0 }, + { "t2", FIELD_t2, -1, 0, 0, 0, 0, 0, 0 }, + { "s2", FIELD_s2, -1, 0, 0, 0, 0, 0, 0 }, + { "r2", FIELD_r2, -1, 0, 0, 0, 0, 0, 0 }, + { "t4", FIELD_t4, -1, 0, 0, 0, 0, 0, 0 }, + { "s4", FIELD_s4, -1, 0, 0, 0, 0, 0, 0 }, + { "r4", FIELD_r4, -1, 0, 0, 0, 0, 0, 0 }, + { "t8", FIELD_t8, -1, 0, 0, 0, 0, 0, 0 }, + { "s8", FIELD_s8, -1, 0, 0, 0, 0, 0, 0 }, + { "r8", FIELD_r8, -1, 0, 0, 0, 0, 0, 0 }, + { "xt_wbr15_imm", FIELD_xt_wbr15_imm, -1, 0, 0, 0, 0, 0, 0 }, + { "xt_wbr18_imm", FIELD_xt_wbr18_imm, -1, 0, 0, 0, 0, 0, 0 }, + { "dfp_fld_op1", FIELD_dfp_fld_op1, -1, 0, 0, 0, 0, 0, 0 }, + { "dfp_fld_r_3", FIELD_dfp_fld_r_3, -1, 0, 0, 0, 0, 0, 0 }, + { "dfp_fld_r_3_1", FIELD_dfp_fld_r_3_1, -1, 0, 0, 0, 0, 0, 0 }, + { "dfp_fld_s_3_1", FIELD_dfp_fld_s_3_1, -1, 0, 0, 0, 0, 0, 0 }, + { "dfp_fld_op2_3", FIELD_dfp_fld_op2_3, -1, 0, 0, 0, 0, 0, 0 }, + { "dfp_fld_op2_3_2", FIELD_dfp_fld_op2_3_2, -1, 0, 0, 0, 0, 0, 0 }, + { "dfp_fld_op2_3_1", FIELD_dfp_fld_op2_3_1, -1, 0, 0, 0, 0, 0, 0 }, + { "s3to1", FIELD_s3to1, -1, 0, 0, 0, 0, 0, 0 } +}; + +enum xtensa_operand_id { + OPERAND_soffsetx4, + OPERAND_uimm12x8, + OPERAND_simm4, + OPERAND_arr, + OPERAND_ars, + OPERAND__ars_invisible, + OPERAND_art, + OPERAND_ar0, + OPERAND_ar4, + OPERAND_ar8, + OPERAND_ar12, + OPERAND_ars_entry, + OPERAND_immrx4, + OPERAND_lsi4x4, + OPERAND_simm7, + OPERAND_uimm6, + OPERAND_ai4const, + OPERAND_b4const, + OPERAND_b4constu, + OPERAND_uimm8, + OPERAND_uimm8x2, + OPERAND_uimm8x4, + OPERAND_uimm4x16, + OPERAND_uimmrx4, + OPERAND_simm8, + OPERAND_simm8x256, + OPERAND_simm12b, + OPERAND_msalp32, + OPERAND_op2p1, + OPERAND_label8, + OPERAND_ulabel8, + OPERAND_label12, + OPERAND_soffset, + OPERAND_uimm16x4, + OPERAND_bbi, + OPERAND_sae, + OPERAND_sas, + OPERAND_sargt, + OPERAND_s, + OPERAND_mx, + OPERAND_my, + OPERAND_mw, + OPERAND_mr0, + OPERAND_mr1, + OPERAND_mr2, + OPERAND_mr3, + OPERAND_immt, + OPERAND_imms, + OPERAND_bt, + OPERAND_bs, + OPERAND_br, + OPERAND_bt2, + OPERAND_bs2, + OPERAND_br2, + OPERAND_bt4, + OPERAND_bs4, + OPERAND_br4, + OPERAND_bt8, + OPERAND_bs8, + OPERAND_br8, + OPERAND_bt16, + OPERAND_bs16, + OPERAND_br16, + OPERAND_brall, + OPERAND_tp7, + OPERAND_xt_wbr15_label, + OPERAND_xt_wbr18_label, + OPERAND_dfp_fld_op2_2, + OPERAND_dfp_fld_op2_1_0, + OPERAND_dfp_fld_r_0, + OPERAND_dfp_fld_r_2_1, + OPERAND_dfp_fld_op2, + OPERAND_dfp_fld_op2_0, + OPERAND_dfp_fld_s_0, + OPERAND_frr, + OPERAND_frs, + OPERAND_frt, + OPERAND_imm_t, + OPERAND_imm_s, + OPERAND_imm8x4, + OPERAND_imm8x8, + OPERAND_bitindex, + OPERAND_t, + OPERAND_bbi4, + OPERAND_imm12, + OPERAND_imm8, + OPERAND_imm12b, + OPERAND_imm16, + OPERAND_m, + OPERAND_n, + OPERAND_offset, + OPERAND_op0, + OPERAND_op1, + OPERAND_op2, + OPERAND_r, + OPERAND_sa4, + OPERAND_sae4, + OPERAND_sal, + OPERAND_sas4, + OPERAND_sr, + OPERAND_st, + OPERAND_thi3, + OPERAND_imm4, + OPERAND_mn, + OPERAND_i, + OPERAND_imm6lo, + OPERAND_imm6hi, + OPERAND_imm7lo, + OPERAND_imm7hi, + OPERAND_z, + OPERAND_imm6, + OPERAND_imm7, + OPERAND_r3, + OPERAND_rbit2, + OPERAND_rhi, + OPERAND_t3, + OPERAND_tbit2, + OPERAND_tlo, + OPERAND_w, + OPERAND_y, + OPERAND_x, + OPERAND_t2, + OPERAND_s2, + OPERAND_r2, + OPERAND_t4, + OPERAND_s4, + OPERAND_r4, + OPERAND_t8, + OPERAND_s8, + OPERAND_r8, + OPERAND_xt_wbr15_imm, + OPERAND_xt_wbr18_imm, + OPERAND_dfp_fld_op1, + OPERAND_dfp_fld_r_3, + OPERAND_dfp_fld_r_3_1, + OPERAND_dfp_fld_s_3_1, + OPERAND_dfp_fld_op2_3, + OPERAND_dfp_fld_op2_3_2, + OPERAND_dfp_fld_op2_3_1, + OPERAND_s3to1 +}; + + +/* Iclass table. */ + +static xtensa_arg_internal Iclass_LSI_args[] = { + { { OPERAND_frt }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_imm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_LSI_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_LSIP_args[] = { + { { OPERAND_frt }, 'o' }, + { { OPERAND_ars }, 'm' }, + { { OPERAND_imm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_LSIP_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_LSX_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_LSX_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_LSXP_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_ars }, 'm' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_LSXP_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_SSI_args[] = { + { { OPERAND_frt }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_imm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_SSI_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_SSIP_args[] = { + { { OPERAND_frt }, 'i' }, + { { OPERAND_ars }, 'm' }, + { { OPERAND_imm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_SSIP_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_SSX_args[] = { + { { OPERAND_frr }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_SSX_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_SSXP_args[] = { + { { OPERAND_frr }, 'i' }, + { { OPERAND_ars }, 'm' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_SSXP_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_ABS_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_frs }, 'i' } +}; + +static xtensa_arg_internal Iclass_ABS_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_NEG_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_frs }, 'i' } +}; + +static xtensa_arg_internal Iclass_NEG_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_MOV_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_frs }, 'i' } +}; + +static xtensa_arg_internal Iclass_MOV_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_MOVEQZ_S_args[] = { + { { OPERAND_frr }, 'm' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_MOVEQZ_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_MOVNEZ_S_args[] = { + { { OPERAND_frr }, 'm' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_MOVNEZ_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_MOVLTZ_S_args[] = { + { { OPERAND_frr }, 'm' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_MOVLTZ_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_MOVGEZ_S_args[] = { + { { OPERAND_frr }, 'm' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_MOVGEZ_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_MOVF_S_args[] = { + { { OPERAND_frr }, 'm' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_bt }, 'i' } +}; + +static xtensa_arg_internal Iclass_MOVF_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_MOVT_S_args[] = { + { { OPERAND_frr }, 'm' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_bt }, 'i' } +}; + +static xtensa_arg_internal Iclass_MOVT_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_WFR_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_WFR_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_RFR_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_frs }, 'i' } +}; + +static xtensa_arg_internal Iclass_RFR_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_ROUND_S_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_imm_t }, 'i' } +}; + +static xtensa_arg_internal Iclass_ROUND_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_InexactFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_CEIL_S_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_imm_t }, 'i' } +}; + +static xtensa_arg_internal Iclass_CEIL_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_InexactFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_FLOOR_S_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_imm_t }, 'i' } +}; + +static xtensa_arg_internal Iclass_FLOOR_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_InexactFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_TRUNC_S_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_imm_t }, 'i' } +}; + +static xtensa_arg_internal Iclass_TRUNC_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_InexactFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_UTRUNC_S_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_imm_t }, 'i' } +}; + +static xtensa_arg_internal Iclass_UTRUNC_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_InexactFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_FLOAT_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_imm_t }, 'i' } +}; + +static xtensa_arg_internal Iclass_FLOAT_S_stateArgs[] = { + { { STATE_InexactFlag }, 'm' }, + { { STATE_RoundMode }, 'i' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_UFLOAT_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_imm_t }, 'i' } +}; + +static xtensa_arg_internal Iclass_UFLOAT_S_stateArgs[] = { + { { STATE_InexactFlag }, 'm' }, + { { STATE_RoundMode }, 'i' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_UN_S_args[] = { + { { OPERAND_br }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_frt }, 'i' } +}; + +static xtensa_arg_internal Iclass_UN_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_ULT_S_args[] = { + { { OPERAND_br }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_frt }, 'i' } +}; + +static xtensa_arg_internal Iclass_ULT_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_ULE_S_args[] = { + { { OPERAND_br }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_frt }, 'i' } +}; + +static xtensa_arg_internal Iclass_ULE_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_UEQ_S_args[] = { + { { OPERAND_br }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_frt }, 'i' } +}; + +static xtensa_arg_internal Iclass_UEQ_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_OLT_S_args[] = { + { { OPERAND_br }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_frt }, 'i' } +}; + +static xtensa_arg_internal Iclass_OLT_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_OLE_S_args[] = { + { { OPERAND_br }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_frt }, 'i' } +}; + +static xtensa_arg_internal Iclass_OLE_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_OEQ_S_args[] = { + { { OPERAND_br }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_frt }, 'i' } +}; + +static xtensa_arg_internal Iclass_OEQ_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_ADD_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_frt }, 'i' } +}; + +static xtensa_arg_internal Iclass_ADD_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_OverflowFlag }, 'm' }, + { { STATE_UnderflowFlag }, 'm' }, + { { STATE_InexactFlag }, 'm' }, + { { STATE_RoundMode }, 'i' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_SUB_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_frt }, 'i' } +}; + +static xtensa_arg_internal Iclass_SUB_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_OverflowFlag }, 'm' }, + { { STATE_UnderflowFlag }, 'm' }, + { { STATE_InexactFlag }, 'm' }, + { { STATE_RoundMode }, 'i' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_MUL_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_frt }, 'i' } +}; + +static xtensa_arg_internal Iclass_MUL_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_OverflowFlag }, 'm' }, + { { STATE_UnderflowFlag }, 'm' }, + { { STATE_InexactFlag }, 'm' }, + { { STATE_RoundMode }, 'i' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_MADD_S_args[] = { + { { OPERAND_frr }, 'm' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_frt }, 'i' } +}; + +static xtensa_arg_internal Iclass_MADD_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_OverflowFlag }, 'm' }, + { { STATE_UnderflowFlag }, 'm' }, + { { STATE_InexactFlag }, 'm' }, + { { STATE_RoundMode }, 'i' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_MSUB_S_args[] = { + { { OPERAND_frr }, 'm' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_frt }, 'i' } +}; + +static xtensa_arg_internal Iclass_MSUB_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_OverflowFlag }, 'm' }, + { { STATE_UnderflowFlag }, 'm' }, + { { STATE_InexactFlag }, 'm' }, + { { STATE_RoundMode }, 'i' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_SQRT0_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_frs }, 'i' } +}; + +static xtensa_arg_internal Iclass_SQRT0_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_DIV0_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_frs }, 'i' } +}; + +static xtensa_arg_internal Iclass_DIV0_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_RECIP0_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_frs }, 'i' } +}; + +static xtensa_arg_internal Iclass_RECIP0_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_DivZeroFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_RSQRT0_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_frs }, 'i' } +}; + +static xtensa_arg_internal Iclass_RSQRT0_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_DivZeroFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_MADDN_S_args[] = { + { { OPERAND_frr }, 'm' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_frt }, 'i' } +}; + +static xtensa_arg_internal Iclass_MADDN_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_DIVN_S_args[] = { + { { OPERAND_frr }, 'm' }, + { { OPERAND_frs }, 'i' }, + { { OPERAND_frt }, 'i' } +}; + +static xtensa_arg_internal Iclass_DIVN_S_stateArgs[] = { + { { STATE_OverflowFlag }, 'm' }, + { { STATE_UnderflowFlag }, 'm' }, + { { STATE_InexactFlag }, 'm' }, + { { STATE_RoundMode }, 'i' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_CONST_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_imm_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_CONST_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_NEXP01_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_frs }, 'i' } +}; + +static xtensa_arg_internal Iclass_NEXP01_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_ADDEXP_S_args[] = { + { { OPERAND_frr }, 'm' }, + { { OPERAND_frs }, 'i' } +}; + +static xtensa_arg_internal Iclass_ADDEXP_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_ADDEXPM_S_args[] = { + { { OPERAND_frr }, 'm' }, + { { OPERAND_frs }, 'i' } +}; + +static xtensa_arg_internal Iclass_ADDEXPM_S_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_MKDADJ_S_args[] = { + { { OPERAND_frr }, 'm' }, + { { OPERAND_frs }, 'i' } +}; + +static xtensa_arg_internal Iclass_MKDADJ_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_DivZeroFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_MKSADJ_S_args[] = { + { { OPERAND_frr }, 'o' }, + { { OPERAND_frs }, 'i' } +}; + +static xtensa_arg_internal Iclass_MKSADJ_S_stateArgs[] = { + { { STATE_InvalidFlag }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfe_stateArgs[] = { + { { STATE_PSEXCM }, 'o' }, + { { STATE_EPC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfde_stateArgs[] = { + { { STATE_DEPC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call12_args[] = { + { { OPERAND_soffsetx4 }, 'i' }, + { { OPERAND_ar12 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call12_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call8_args[] = { + { { OPERAND_soffsetx4 }, 'i' }, + { { OPERAND_ar8 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call8_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call4_args[] = { + { { OPERAND_soffsetx4 }, 'i' }, + { { OPERAND_ar4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call4_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx12_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_ar12 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx12_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx8_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_ar8 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx8_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx4_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_ar4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx4_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_entry_args[] = { + { { OPERAND_ars_entry }, 's' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm12x8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_entry_stateArgs[] = { + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSWOE }, 'i' }, + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movsp_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movsp_stateArgs[] = { + { { STATE_WindowBase }, 'i' }, + { { STATE_WindowStart }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rotw_args[] = { + { { OPERAND_simm4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rotw_stateArgs[] = { + { { STATE_WindowBase }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_retw_args[] = { + { { OPERAND__ars_invisible }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_retw_stateArgs[] = { + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSWOE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfwou_stateArgs[] = { + { { STATE_EPC1 }, 'i' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' }, + { { STATE_PSOWB }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32e_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_immrx4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32e_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_immrx4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowbase_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowbase_stateArgs[] = { + { { STATE_WindowBase }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowbase_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowbase_stateArgs[] = { + { { STATE_WindowBase }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowbase_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowbase_stateArgs[] = { + { { STATE_WindowBase }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowstart_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowstart_stateArgs[] = { + { { STATE_WindowStart }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowstart_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowstart_stateArgs[] = { + { { STATE_WindowStart }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowstart_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowstart_stateArgs[] = { + { { STATE_WindowStart }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_add_n_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addi_n_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_ai4const }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bz6_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loadi4_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_lsi4x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mov_n_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movi_n_args[] = { + { { OPERAND_ars }, 'o' }, + { { OPERAND_simm7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_retn_args[] = { + { { OPERAND__ars_invisible }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_storei4_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_lsi4x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_rur_threadptr_args[] = { + { { OPERAND_arr }, 'o' } +}; + +static xtensa_arg_internal Iclass_rur_threadptr_stateArgs[] = { + { { STATE_THREADPTR }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_threadptr_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_threadptr_stateArgs[] = { + { { STATE_THREADPTR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addi_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_simm8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addmi_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_simm8x256 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addsub_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bit_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_b4const }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8b_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_bbi }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8u_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_b4constu }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bst8_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsz12_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_label12 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call0_args[] = { + { { OPERAND_soffsetx4 }, 'i' }, + { { OPERAND_ar0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx0_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_ar0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_exti_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_sae }, 'i' }, + { { OPERAND_op2p1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_jump_args[] = { + { { OPERAND_soffset }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_jumpx_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l16ui_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l16si_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32i_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32r_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_uimm16x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l8i_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loop_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_ulabel8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loop_stateArgs[] = { + { { STATE_LBEG }, 'o' }, + { { STATE_LEND }, 'o' }, + { { STATE_LCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loopz_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_ulabel8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loopz_stateArgs[] = { + { { STATE_LBEG }, 'o' }, + { { STATE_LEND }, 'o' }, + { { STATE_LCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movi_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_simm12b }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movz_args[] = { + { { OPERAND_arr }, 'm' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_neg_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_return_args[] = { + { { OPERAND__ars_invisible }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s16i_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32i_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32nb_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimmrx4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s8i_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sar_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sar_stateArgs[] = { + { { STATE_SAR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sari_args[] = { + { { OPERAND_sas }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sari_stateArgs[] = { + { { STATE_SAR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shifts_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shifts_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftst_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftst_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftt_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftt_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_slli_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_msalp32 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_srai_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_sargt }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_srli_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sync_stateArgs[] = { + { { STATE_XTSYNC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsil_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsil_stateArgs[] = { + { { STATE_PSWOE }, 'i' }, + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSOWB }, 'i' }, + { { STATE_PSUM }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lend_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lend_stateArgs[] = { + { { STATE_LEND }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lend_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lend_stateArgs[] = { + { { STATE_LEND }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lend_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lend_stateArgs[] = { + { { STATE_LEND }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lcount_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lcount_stateArgs[] = { + { { STATE_LCOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lcount_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lcount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_LCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lcount_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lcount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_LCOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lbeg_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lbeg_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lbeg_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_sar_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_sar_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_sar_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_sar_stateArgs[] = { + { { STATE_SAR }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_sar_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_sar_stateArgs[] = { + { { STATE_SAR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_memctl_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_memctl_stateArgs[] = { + { { STATE_MEMCTL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_memctl_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_memctl_stateArgs[] = { + { { STATE_MEMCTL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_memctl_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_memctl_stateArgs[] = { + { { STATE_MEMCTL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_litbase_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_litbase_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_litbase_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_configid0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_configid0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_configid1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ps_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'i' }, + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSOWB }, 'i' }, + { { STATE_PSUM }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ps_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ps_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'm' }, + { { STATE_PSCALLINC }, 'm' }, + { { STATE_PSOWB }, 'm' }, + { { STATE_PSUM }, 'm' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSINTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc1_stateArgs[] = { + { { STATE_EPC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc1_stateArgs[] = { + { { STATE_EPC1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc1_stateArgs[] = { + { { STATE_EPC1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave1_stateArgs[] = { + { { STATE_EXCSAVE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave1_stateArgs[] = { + { { STATE_EXCSAVE1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave1_stateArgs[] = { + { { STATE_EXCSAVE1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc2_stateArgs[] = { + { { STATE_EPC2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc2_stateArgs[] = { + { { STATE_EPC2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc2_stateArgs[] = { + { { STATE_EPC2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave2_stateArgs[] = { + { { STATE_EXCSAVE2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave2_stateArgs[] = { + { { STATE_EXCSAVE2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave2_stateArgs[] = { + { { STATE_EXCSAVE2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc3_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc3_stateArgs[] = { + { { STATE_EPC3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc3_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc3_stateArgs[] = { + { { STATE_EPC3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc3_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc3_stateArgs[] = { + { { STATE_EPC3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave3_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave3_stateArgs[] = { + { { STATE_EXCSAVE3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave3_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave3_stateArgs[] = { + { { STATE_EXCSAVE3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave3_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave3_stateArgs[] = { + { { STATE_EXCSAVE3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc4_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc4_stateArgs[] = { + { { STATE_EPC4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc4_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc4_stateArgs[] = { + { { STATE_EPC4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc4_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc4_stateArgs[] = { + { { STATE_EPC4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave4_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave4_stateArgs[] = { + { { STATE_EXCSAVE4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave4_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave4_stateArgs[] = { + { { STATE_EXCSAVE4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave4_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave4_stateArgs[] = { + { { STATE_EXCSAVE4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc5_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc5_stateArgs[] = { + { { STATE_EPC5 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc5_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc5_stateArgs[] = { + { { STATE_EPC5 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc5_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc5_stateArgs[] = { + { { STATE_EPC5 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave5_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave5_stateArgs[] = { + { { STATE_EXCSAVE5 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave5_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave5_stateArgs[] = { + { { STATE_EXCSAVE5 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave5_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave5_stateArgs[] = { + { { STATE_EXCSAVE5 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc6_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc6_stateArgs[] = { + { { STATE_EPC6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc6_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc6_stateArgs[] = { + { { STATE_EPC6 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc6_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc6_stateArgs[] = { + { { STATE_EPC6 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave6_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave6_stateArgs[] = { + { { STATE_EXCSAVE6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave6_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave6_stateArgs[] = { + { { STATE_EXCSAVE6 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave6_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave6_stateArgs[] = { + { { STATE_EXCSAVE6 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc7_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc7_stateArgs[] = { + { { STATE_EPC7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc7_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc7_stateArgs[] = { + { { STATE_EPC7 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc7_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc7_stateArgs[] = { + { { STATE_EPC7 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave7_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave7_stateArgs[] = { + { { STATE_EXCSAVE7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave7_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave7_stateArgs[] = { + { { STATE_EXCSAVE7 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave7_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave7_stateArgs[] = { + { { STATE_EXCSAVE7 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps2_stateArgs[] = { + { { STATE_EPS2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps2_stateArgs[] = { + { { STATE_EPS2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps2_stateArgs[] = { + { { STATE_EPS2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps3_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps3_stateArgs[] = { + { { STATE_EPS3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps3_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps3_stateArgs[] = { + { { STATE_EPS3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps3_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps3_stateArgs[] = { + { { STATE_EPS3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps4_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps4_stateArgs[] = { + { { STATE_EPS4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps4_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps4_stateArgs[] = { + { { STATE_EPS4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps4_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps4_stateArgs[] = { + { { STATE_EPS4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps5_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps5_stateArgs[] = { + { { STATE_EPS5 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps5_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps5_stateArgs[] = { + { { STATE_EPS5 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps5_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps5_stateArgs[] = { + { { STATE_EPS5 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps6_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps6_stateArgs[] = { + { { STATE_EPS6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps6_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps6_stateArgs[] = { + { { STATE_EPS6 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps6_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps6_stateArgs[] = { + { { STATE_EPS6 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps7_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps7_stateArgs[] = { + { { STATE_EPS7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps7_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps7_stateArgs[] = { + { { STATE_EPS7 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps7_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps7_stateArgs[] = { + { { STATE_EPS7 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excvaddr_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excvaddr_stateArgs[] = { + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excvaddr_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excvaddr_stateArgs[] = { + { { STATE_EXCVADDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excvaddr_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excvaddr_stateArgs[] = { + { { STATE_EXCVADDR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_depc_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_depc_stateArgs[] = { + { { STATE_DEPC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_depc_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_depc_stateArgs[] = { + { { STATE_DEPC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_depc_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_depc_stateArgs[] = { + { { STATE_DEPC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_exccause_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_exccause_stateArgs[] = { + { { STATE_EXCCAUSE }, 'i' }, + { { STATE_XTSYNC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_exccause_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_exccause_stateArgs[] = { + { { STATE_EXCCAUSE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_exccause_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_exccause_stateArgs[] = { + { { STATE_EXCCAUSE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc0_stateArgs[] = { + { { STATE_MISC0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc0_stateArgs[] = { + { { STATE_MISC0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc0_stateArgs[] = { + { { STATE_MISC0 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc1_stateArgs[] = { + { { STATE_MISC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc1_stateArgs[] = { + { { STATE_MISC1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc1_stateArgs[] = { + { { STATE_MISC1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc2_stateArgs[] = { + { { STATE_MISC2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc2_stateArgs[] = { + { { STATE_MISC2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc2_stateArgs[] = { + { { STATE_MISC2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc3_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc3_stateArgs[] = { + { { STATE_MISC3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc3_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc3_stateArgs[] = { + { { STATE_MISC3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc3_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc3_stateArgs[] = { + { { STATE_MISC3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_prid_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_vecbase_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_vecbase_stateArgs[] = { + { { STATE_VECBASE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_vecbase_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_vecbase_stateArgs[] = { + { { STATE_VECBASE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_vecbase_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_vecbase_stateArgs[] = { + { { STATE_VECBASE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_mul16_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_mul32_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_mul32h_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_aa_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_aa_stateArgs[] = { + { { STATE_ACC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_ad_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_my }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_ad_stateArgs[] = { + { { STATE_ACC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_da_args[] = { + { { OPERAND_mx }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_da_stateArgs[] = { + { { STATE_ACC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_dd_args[] = { + { { OPERAND_mx }, 'i' }, + { { OPERAND_my }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_dd_stateArgs[] = { + { { STATE_ACC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_aa_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_aa_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_ad_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_my }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_ad_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_da_args[] = { + { { OPERAND_mx }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_da_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_dd_args[] = { + { { OPERAND_mx }, 'i' }, + { { OPERAND_my }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_dd_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16al_da_args[] = { + { { OPERAND_mw }, 'o' }, + { { OPERAND_ars }, 'm' }, + { { OPERAND_mx }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16al_da_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16al_dd_args[] = { + { { OPERAND_mw }, 'o' }, + { { OPERAND_ars }, 'm' }, + { { OPERAND_mx }, 'i' }, + { { OPERAND_my }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16al_dd_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_l_args[] = { + { { OPERAND_mw }, 'o' }, + { { OPERAND_ars }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_m0_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_mr0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_m0_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_mr0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_m0_args[] = { + { { OPERAND_art }, 'm' }, + { { OPERAND_mr0 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_m1_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_mr1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_m1_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_mr1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_m1_args[] = { + { { OPERAND_art }, 'm' }, + { { OPERAND_mr1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_m2_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_mr2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_m2_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_mr2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_m2_args[] = { + { { OPERAND_art }, 'm' }, + { { OPERAND_mr2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_m3_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_mr3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_m3_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_mr3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_m3_args[] = { + { { OPERAND_art }, 'm' }, + { { OPERAND_mr3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_acclo_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_acclo_stateArgs[] = { + { { STATE_ACC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_acclo_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_acclo_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_acclo_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_acclo_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_acchi_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_acchi_stateArgs[] = { + { { STATE_ACC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_acchi_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_acchi_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_acchi_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_acchi_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfi_args[] = { + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfi_stateArgs[] = { + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' }, + { { STATE_EPC1 }, 'i' }, + { { STATE_EPC2 }, 'i' }, + { { STATE_EPC3 }, 'i' }, + { { STATE_EPC4 }, 'i' }, + { { STATE_EPC5 }, 'i' }, + { { STATE_EPC6 }, 'i' }, + { { STATE_EPC7 }, 'i' }, + { { STATE_EPS2 }, 'i' }, + { { STATE_EPS3 }, 'i' }, + { { STATE_EPS4 }, 'i' }, + { { STATE_EPS5 }, 'i' }, + { { STATE_EPS6 }, 'i' }, + { { STATE_EPS7 }, 'i' }, + { { STATE_InOCDMode }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wait_args[] = { + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wait_stateArgs[] = { + { { STATE_PSINTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_interrupt_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_interrupt_stateArgs[] = { + { { STATE_INTERRUPT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intset_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intset_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intclear_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intclear_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_intenable_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_intenable_stateArgs[] = { + { { STATE_INTENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intenable_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intenable_stateArgs[] = { + { { STATE_INTENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_intenable_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_intenable_stateArgs[] = { + { { STATE_INTENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_args[] = { + { { OPERAND_imms }, 'i' }, + { { OPERAND_immt }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_n_args[] = { + { { OPERAND_imms }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_n_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka0_stateArgs[] = { + { { STATE_DBREAKA0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka0_stateArgs[] = { + { { STATE_DBREAKA0 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka0_stateArgs[] = { + { { STATE_DBREAKA0 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc0_stateArgs[] = { + { { STATE_DBREAKC0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc0_stateArgs[] = { + { { STATE_DBREAKC0 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc0_stateArgs[] = { + { { STATE_DBREAKC0 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka1_stateArgs[] = { + { { STATE_DBREAKA1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka1_stateArgs[] = { + { { STATE_DBREAKA1 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka1_stateArgs[] = { + { { STATE_DBREAKA1 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc1_stateArgs[] = { + { { STATE_DBREAKC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc1_stateArgs[] = { + { { STATE_DBREAKC1 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc1_stateArgs[] = { + { { STATE_DBREAKC1 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka0_stateArgs[] = { + { { STATE_IBREAKA0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka0_stateArgs[] = { + { { STATE_IBREAKA0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka0_stateArgs[] = { + { { STATE_IBREAKA0 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka1_stateArgs[] = { + { { STATE_IBREAKA1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka1_stateArgs[] = { + { { STATE_IBREAKA1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka1_stateArgs[] = { + { { STATE_IBREAKA1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreakenable_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreakenable_stateArgs[] = { + { { STATE_IBREAKENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreakenable_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreakenable_stateArgs[] = { + { { STATE_IBREAKENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreakenable_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreakenable_stateArgs[] = { + { { STATE_IBREAKENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_debugcause_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_debugcause_stateArgs[] = { + { { STATE_DEBUGCAUSE }, 'i' }, + { { STATE_DBNUM }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_debugcause_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_debugcause_stateArgs[] = { + { { STATE_DEBUGCAUSE }, 'o' }, + { { STATE_DBNUM }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_debugcause_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_debugcause_stateArgs[] = { + { { STATE_DEBUGCAUSE }, 'm' }, + { { STATE_DBNUM }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icount_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icount_stateArgs[] = { + { { STATE_ICOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icount_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_ICOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icount_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_ICOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icountlevel_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icountlevel_stateArgs[] = { + { { STATE_ICOUNTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icountlevel_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icountlevel_stateArgs[] = { + { { STATE_ICOUNTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icountlevel_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icountlevel_stateArgs[] = { + { { STATE_ICOUNTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ddr_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ddr_stateArgs[] = { + { { STATE_DDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ddr_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ddr_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_DDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ddr_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ddr_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_DDR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_lddr32_p_args[] = { + { { OPERAND_ars }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_lddr32_p_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_InOCDMode }, 'i' }, + { { STATE_DDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sddr32_p_args[] = { + { { OPERAND_ars }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sddr32_p_stateArgs[] = { + { { STATE_InOCDMode }, 'i' }, + { { STATE_DDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdo_args[] = { + { { OPERAND_imms }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdo_stateArgs[] = { + { { STATE_InOCDMode }, 'm' }, + { { STATE_EPC6 }, 'i' }, + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' }, + { { STATE_EPS6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdd_stateArgs[] = { + { { STATE_InOCDMode }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_mmid_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_mmid_stateArgs[] = { + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bbool1_args[] = { + { { OPERAND_br }, 'o' }, + { { OPERAND_bs }, 'i' }, + { { OPERAND_bt }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bbool4_args[] = { + { { OPERAND_bt }, 'o' }, + { { OPERAND_bs4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bbool8_args[] = { + { { OPERAND_bt }, 'o' }, + { { OPERAND_bs8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bbranch_args[] = { + { { OPERAND_bs }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bmove_args[] = { + { { OPERAND_arr }, 'm' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_bt }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_RSR_BR_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_brall }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_WSR_BR_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_brall }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_XSR_BR_args[] = { + { { OPERAND_art }, 'm' }, + { { OPERAND_brall }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccount_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccount_stateArgs[] = { + { { STATE_CCOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccount_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_CCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccount_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_CCOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare0_stateArgs[] = { + { { STATE_CCOMPARE0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare0_stateArgs[] = { + { { STATE_CCOMPARE0 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare0_stateArgs[] = { + { { STATE_CCOMPARE0 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare1_stateArgs[] = { + { { STATE_CCOMPARE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare1_stateArgs[] = { + { { STATE_CCOMPARE1 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare1_stateArgs[] = { + { { STATE_CCOMPARE1 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare2_stateArgs[] = { + { { STATE_CCOMPARE2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare2_stateArgs[] = { + { { STATE_CCOMPARE2 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare2_stateArgs[] = { + { { STATE_CCOMPARE2 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_idtlb_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_idtlb_stateArgs[] = { + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rdtlb_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wdtlb_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wdtlb_stateArgs[] = { + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_iitlb_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ritlb_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_witlb_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_cpenable_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_cpenable_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_cpenable_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_cpenable_stateArgs[] = { + { { STATE_CPENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_cpenable_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_cpenable_stateArgs[] = { + { { STATE_CPENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_clamp_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_tp7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_minmax_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_nsa_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sx_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_tp7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32ai_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32ri_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32c1i_args[] = { + { { OPERAND_art }, 'm' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32c1i_stateArgs[] = { + { { STATE_SCOMPARE1 }, 'i' }, + { { STATE_XTSYNC }, 'i' }, + { { STATE_SCOMPARE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_scompare1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_scompare1_stateArgs[] = { + { { STATE_SCOMPARE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_scompare1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_scompare1_stateArgs[] = { + { { STATE_SCOMPARE1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_scompare1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_scompare1_stateArgs[] = { + { { STATE_SCOMPARE1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_atomctl_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_atomctl_stateArgs[] = { + { { STATE_ATOMCTL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_atomctl_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_atomctl_stateArgs[] = { + { { STATE_ATOMCTL }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_atomctl_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_atomctl_stateArgs[] = { + { { STATE_ATOMCTL }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_div_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rer_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rer_stateArgs[] = { + { { STATE_ERI_RAW_INTERLOCK }, 'i' } +}; + +static xtensa_interface Iclass_xt_iclass_rer_intfArgs[] = { + INTERFACE_ERI_RD_In, + INTERFACE_ERI_RD_Out +}; + +static xtensa_arg_internal Iclass_xt_iclass_wer_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wer_stateArgs[] = { + { { STATE_ERI_RAW_INTERLOCK }, 'o' } +}; + +static xtensa_interface Iclass_xt_iclass_wer_intfArgs[] = { + INTERFACE_ERI_WR_In, + INTERFACE_ERI_WR_Out +}; + +static xtensa_arg_internal Iclass_iclass_F64ITER_args[] = { + { { OPERAND_arr }, 'm' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_dfp_fld_op2_1_0 }, 'i' }, + { { OPERAND_dfp_fld_op2_2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_F64ITER_stateArgs[] = { + { { STATE_F64R }, 'm' }, + { { STATE_F64S }, 'm' } +}; + +static xtensa_arg_internal Iclass_iclass_F64RND_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_dfp_fld_op2_1_0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_F64RND_stateArgs[] = { + { { STATE_F64R }, 'm' }, + { { STATE_F64S }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_F64ADDC_F64SUBC_args[] = { + { { OPERAND_art }, 'm' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_dfp_fld_r_2_1 }, 'i' }, + { { OPERAND_dfp_fld_r_0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_F64ADDC_F64SUBC_stateArgs[] = { + { { STATE_F64S }, 'm' } +}; + +static xtensa_arg_internal Iclass_iclass_F64SIG_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_F64CMPL_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_F64CMPL_stateArgs[] = { + { { STATE_F64S }, 'o' } +}; + +static xtensa_arg_internal Iclass_iclass_F64CMPH_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_dfp_fld_op2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_F64CMPH_stateArgs[] = { + { { STATE_SAR }, 'o' }, + { { STATE_F64R }, 'o' }, + { { STATE_F64S }, 'm' } +}; + +static xtensa_arg_internal Iclass_iclass_F64NORM_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_dfp_fld_op2_0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_F64NORM_stateArgs[] = { + { { STATE_SAR }, 'o' }, + { { STATE_F64S }, 'm' } +}; + +static xtensa_arg_internal Iclass_iclass_F64SEXP_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_RF64R_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_dfp_fld_s_0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_RF64R_stateArgs[] = { + { { STATE_F64R }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_WF64R_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_dfp_fld_r_0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_WF64R_stateArgs[] = { + { { STATE_F64R }, 'o' } +}; + +static xtensa_arg_internal Iclass_rur_f64r_lo_args[] = { + { { OPERAND_arr }, 'o' } +}; + +static xtensa_arg_internal Iclass_rur_f64r_lo_stateArgs[] = { + { { STATE_F64R }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_f64r_lo_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_f64r_lo_stateArgs[] = { + { { STATE_F64R }, 'm' } +}; + +static xtensa_arg_internal Iclass_rur_f64r_hi_args[] = { + { { OPERAND_arr }, 'o' } +}; + +static xtensa_arg_internal Iclass_rur_f64r_hi_stateArgs[] = { + { { STATE_F64R }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_f64r_hi_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_f64r_hi_stateArgs[] = { + { { STATE_F64R }, 'm' } +}; + +static xtensa_arg_internal Iclass_rur_f64s_args[] = { + { { OPERAND_arr }, 'o' } +}; + +static xtensa_arg_internal Iclass_rur_f64s_stateArgs[] = { + { { STATE_F64S }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_f64s_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_f64s_stateArgs[] = { + { { STATE_F64S }, 'o' } +}; + +static xtensa_arg_internal Iclass_rur_fcr_args[] = { + { { OPERAND_arr }, 'o' } +}; + +static xtensa_arg_internal Iclass_rur_fcr_stateArgs[] = { + { { STATE_RoundMode }, 'i' }, + { { STATE_InvalidEnable }, 'i' }, + { { STATE_DivZeroEnable }, 'i' }, + { { STATE_OverflowEnable }, 'i' }, + { { STATE_UnderflowEnable }, 'i' }, + { { STATE_InexactEnable }, 'i' }, + { { STATE_FPreserved20 }, 'i' }, + { { STATE_FPreserved5 }, 'i' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_fcr_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_fcr_stateArgs[] = { + { { STATE_RoundMode }, 'o' }, + { { STATE_InvalidEnable }, 'o' }, + { { STATE_DivZeroEnable }, 'o' }, + { { STATE_OverflowEnable }, 'o' }, + { { STATE_UnderflowEnable }, 'o' }, + { { STATE_InexactEnable }, 'o' }, + { { STATE_FPreserved20 }, 'o' }, + { { STATE_FPreserved5 }, 'o' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_rur_fsr_args[] = { + { { OPERAND_arr }, 'o' } +}; + +static xtensa_arg_internal Iclass_rur_fsr_stateArgs[] = { + { { STATE_InvalidFlag }, 'i' }, + { { STATE_DivZeroFlag }, 'i' }, + { { STATE_OverflowFlag }, 'i' }, + { { STATE_UnderflowFlag }, 'i' }, + { { STATE_InexactFlag }, 'i' }, + { { STATE_FPreserved20a }, 'i' }, + { { STATE_FPreserved7 }, 'i' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_fsr_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_fsr_stateArgs[] = { + { { STATE_InvalidFlag }, 'o' }, + { { STATE_DivZeroFlag }, 'o' }, + { { STATE_OverflowFlag }, 'o' }, + { { STATE_UnderflowFlag }, 'o' }, + { { STATE_InexactFlag }, 'o' }, + { { STATE_FPreserved20a }, 'o' }, + { { STATE_FPreserved7 }, 'o' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_rur_expstate_args[] = { + { { OPERAND_arr }, 'o' } +}; + +static xtensa_arg_internal Iclass_rur_expstate_stateArgs[] = { + { { STATE_EXPSTATE }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_expstate_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_expstate_stateArgs[] = { + { { STATE_EXPSTATE }, 'o' } +}; + +static xtensa_arg_internal Iclass_iclass_READ_IMPWIRE_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_interface Iclass_iclass_READ_IMPWIRE_intfArgs[] = { + INTERFACE_IMPWIRE +}; + +static xtensa_arg_internal Iclass_iclass_SETB_EXPSTATE_args[] = { + { { OPERAND_bitindex }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_SETB_EXPSTATE_stateArgs[] = { + { { STATE_EXPSTATE }, 'm' } +}; + +static xtensa_arg_internal Iclass_iclass_CLRB_EXPSTATE_args[] = { + { { OPERAND_bitindex }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_CLRB_EXPSTATE_stateArgs[] = { + { { STATE_EXPSTATE }, 'm' } +}; + +static xtensa_arg_internal Iclass_iclass_WRMSK_EXPSTATE_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_WRMSK_EXPSTATE_stateArgs[] = { + { { STATE_EXPSTATE }, 'm' } +}; + +static xtensa_iclass_internal iclasses[] = { + { 3, Iclass_LSI_args, + 1, Iclass_LSI_stateArgs, 0, 0 }, + { 3, Iclass_LSIP_args, + 1, Iclass_LSIP_stateArgs, 0, 0 }, + { 3, Iclass_LSX_args, + 1, Iclass_LSX_stateArgs, 0, 0 }, + { 3, Iclass_LSXP_args, + 1, Iclass_LSXP_stateArgs, 0, 0 }, + { 3, Iclass_SSI_args, + 1, Iclass_SSI_stateArgs, 0, 0 }, + { 3, Iclass_SSIP_args, + 1, Iclass_SSIP_stateArgs, 0, 0 }, + { 3, Iclass_SSX_args, + 1, Iclass_SSX_stateArgs, 0, 0 }, + { 3, Iclass_SSXP_args, + 1, Iclass_SSXP_stateArgs, 0, 0 }, + { 2, Iclass_ABS_S_args, + 1, Iclass_ABS_S_stateArgs, 0, 0 }, + { 2, Iclass_NEG_S_args, + 1, Iclass_NEG_S_stateArgs, 0, 0 }, + { 2, Iclass_MOV_S_args, + 1, Iclass_MOV_S_stateArgs, 0, 0 }, + { 3, Iclass_MOVEQZ_S_args, + 1, Iclass_MOVEQZ_S_stateArgs, 0, 0 }, + { 3, Iclass_MOVNEZ_S_args, + 1, Iclass_MOVNEZ_S_stateArgs, 0, 0 }, + { 3, Iclass_MOVLTZ_S_args, + 1, Iclass_MOVLTZ_S_stateArgs, 0, 0 }, + { 3, Iclass_MOVGEZ_S_args, + 1, Iclass_MOVGEZ_S_stateArgs, 0, 0 }, + { 3, Iclass_MOVF_S_args, + 1, Iclass_MOVF_S_stateArgs, 0, 0 }, + { 3, Iclass_MOVT_S_args, + 1, Iclass_MOVT_S_stateArgs, 0, 0 }, + { 2, Iclass_WFR_args, + 1, Iclass_WFR_stateArgs, 0, 0 }, + { 2, Iclass_RFR_args, + 1, Iclass_RFR_stateArgs, 0, 0 }, + { 3, Iclass_ROUND_S_args, + 3, Iclass_ROUND_S_stateArgs, 0, 0 }, + { 3, Iclass_CEIL_S_args, + 3, Iclass_CEIL_S_stateArgs, 0, 0 }, + { 3, Iclass_FLOOR_S_args, + 3, Iclass_FLOOR_S_stateArgs, 0, 0 }, + { 3, Iclass_TRUNC_S_args, + 3, Iclass_TRUNC_S_stateArgs, 0, 0 }, + { 3, Iclass_UTRUNC_S_args, + 3, Iclass_UTRUNC_S_stateArgs, 0, 0 }, + { 3, Iclass_FLOAT_S_args, + 3, Iclass_FLOAT_S_stateArgs, 0, 0 }, + { 3, Iclass_UFLOAT_S_args, + 3, Iclass_UFLOAT_S_stateArgs, 0, 0 }, + { 3, Iclass_UN_S_args, + 2, Iclass_UN_S_stateArgs, 0, 0 }, + { 3, Iclass_ULT_S_args, + 2, Iclass_ULT_S_stateArgs, 0, 0 }, + { 3, Iclass_ULE_S_args, + 2, Iclass_ULE_S_stateArgs, 0, 0 }, + { 3, Iclass_UEQ_S_args, + 2, Iclass_UEQ_S_stateArgs, 0, 0 }, + { 3, Iclass_OLT_S_args, + 2, Iclass_OLT_S_stateArgs, 0, 0 }, + { 3, Iclass_OLE_S_args, + 2, Iclass_OLE_S_stateArgs, 0, 0 }, + { 3, Iclass_OEQ_S_args, + 2, Iclass_OEQ_S_stateArgs, 0, 0 }, + { 3, Iclass_ADD_S_args, + 6, Iclass_ADD_S_stateArgs, 0, 0 }, + { 3, Iclass_SUB_S_args, + 6, Iclass_SUB_S_stateArgs, 0, 0 }, + { 3, Iclass_MUL_S_args, + 6, Iclass_MUL_S_stateArgs, 0, 0 }, + { 3, Iclass_MADD_S_args, + 6, Iclass_MADD_S_stateArgs, 0, 0 }, + { 3, Iclass_MSUB_S_args, + 6, Iclass_MSUB_S_stateArgs, 0, 0 }, + { 2, Iclass_SQRT0_S_args, + 1, Iclass_SQRT0_S_stateArgs, 0, 0 }, + { 2, Iclass_DIV0_S_args, + 1, Iclass_DIV0_S_stateArgs, 0, 0 }, + { 2, Iclass_RECIP0_S_args, + 3, Iclass_RECIP0_S_stateArgs, 0, 0 }, + { 2, Iclass_RSQRT0_S_args, + 3, Iclass_RSQRT0_S_stateArgs, 0, 0 }, + { 3, Iclass_MADDN_S_args, + 1, Iclass_MADDN_S_stateArgs, 0, 0 }, + { 3, Iclass_DIVN_S_args, + 5, Iclass_DIVN_S_stateArgs, 0, 0 }, + { 2, Iclass_CONST_S_args, + 1, Iclass_CONST_S_stateArgs, 0, 0 }, + { 2, Iclass_NEXP01_S_args, + 1, Iclass_NEXP01_S_stateArgs, 0, 0 }, + { 2, Iclass_ADDEXP_S_args, + 1, Iclass_ADDEXP_S_stateArgs, 0, 0 }, + { 2, Iclass_ADDEXPM_S_args, + 1, Iclass_ADDEXPM_S_stateArgs, 0, 0 }, + { 2, Iclass_MKDADJ_S_args, + 3, Iclass_MKDADJ_S_stateArgs, 0, 0 }, + { 2, Iclass_MKSADJ_S_args, + 2, Iclass_MKSADJ_S_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_excw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_rfe */, + 2, Iclass_xt_iclass_rfe_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfde */, + 1, Iclass_xt_iclass_rfde_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_syscall */, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_call12_args, + 1, Iclass_xt_iclass_call12_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_call8_args, + 1, Iclass_xt_iclass_call8_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_call4_args, + 1, Iclass_xt_iclass_call4_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx12_args, + 1, Iclass_xt_iclass_callx12_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx8_args, + 1, Iclass_xt_iclass_callx8_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx4_args, + 1, Iclass_xt_iclass_callx4_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_entry_args, + 5, Iclass_xt_iclass_entry_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_movsp_args, + 2, Iclass_xt_iclass_movsp_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rotw_args, + 1, Iclass_xt_iclass_rotw_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_retw_args, + 5, Iclass_xt_iclass_retw_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfwou */, + 5, Iclass_xt_iclass_rfwou_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_l32e_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32e_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_windowbase_args, + 1, Iclass_xt_iclass_rsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_windowbase_args, + 1, Iclass_xt_iclass_wsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_windowbase_args, + 1, Iclass_xt_iclass_xsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_windowstart_args, + 1, Iclass_xt_iclass_rsr_windowstart_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_windowstart_args, + 1, Iclass_xt_iclass_wsr_windowstart_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_windowstart_args, + 1, Iclass_xt_iclass_xsr_windowstart_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_add_n_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addi_n_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bz6_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_ill_n */, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_loadi4_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_mov_n_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_movi_n_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_nopn */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_retn_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_storei4_args, + 0, 0, 0, 0 }, + { 1, Iclass_rur_threadptr_args, + 1, Iclass_rur_threadptr_stateArgs, 0, 0 }, + { 1, Iclass_wur_threadptr_args, + 1, Iclass_wur_threadptr_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_addi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addmi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addsub_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bit_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8b_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8u_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bst8_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bsz12_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_call0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_callx0_args, + 0, 0, 0, 0 }, + { 4, Iclass_xt_iclass_exti_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_ill */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_jump_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_jumpx_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l16ui_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l16si_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l32i_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_l32r_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l8i_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_loop_args, + 3, Iclass_xt_iclass_loop_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_loopz_args, + 3, Iclass_xt_iclass_loopz_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_movi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_movz_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_neg_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_nop */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_return_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_simcall */, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s16i_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32i_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32nb_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s8i_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_sar_args, + 1, Iclass_xt_iclass_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_sari_args, + 1, Iclass_xt_iclass_sari_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_shifts_args, + 1, Iclass_xt_iclass_shifts_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_shiftst_args, + 1, Iclass_xt_iclass_shiftst_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_shiftt_args, + 1, Iclass_xt_iclass_shiftt_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_slli_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_srai_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_srli_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_memw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_extw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_isync */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_sync */, + 1, Iclass_xt_iclass_sync_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_rsil_args, + 6, Iclass_xt_iclass_rsil_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lend_args, + 1, Iclass_xt_iclass_rsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lend_args, + 1, Iclass_xt_iclass_wsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lend_args, + 1, Iclass_xt_iclass_xsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lcount_args, + 1, Iclass_xt_iclass_rsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lcount_args, + 2, Iclass_xt_iclass_wsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lcount_args, + 2, Iclass_xt_iclass_xsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lbeg_args, + 1, Iclass_xt_iclass_rsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lbeg_args, + 1, Iclass_xt_iclass_wsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lbeg_args, + 1, Iclass_xt_iclass_xsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_sar_args, + 1, Iclass_xt_iclass_rsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_sar_args, + 2, Iclass_xt_iclass_wsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_sar_args, + 1, Iclass_xt_iclass_xsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_memctl_args, + 1, Iclass_xt_iclass_rsr_memctl_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_memctl_args, + 1, Iclass_xt_iclass_wsr_memctl_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_memctl_args, + 1, Iclass_xt_iclass_xsr_memctl_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_litbase_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_litbase_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_litbase_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_configid0_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_configid0_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_configid1_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ps_args, + 6, Iclass_xt_iclass_rsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ps_args, + 6, Iclass_xt_iclass_wsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ps_args, + 6, Iclass_xt_iclass_xsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc1_args, + 1, Iclass_xt_iclass_rsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc1_args, + 1, Iclass_xt_iclass_wsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc1_args, + 1, Iclass_xt_iclass_xsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave1_args, + 1, Iclass_xt_iclass_rsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave1_args, + 1, Iclass_xt_iclass_wsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave1_args, + 1, Iclass_xt_iclass_xsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc2_args, + 1, Iclass_xt_iclass_rsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc2_args, + 1, Iclass_xt_iclass_wsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc2_args, + 1, Iclass_xt_iclass_xsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave2_args, + 1, Iclass_xt_iclass_rsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave2_args, + 1, Iclass_xt_iclass_wsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave2_args, + 1, Iclass_xt_iclass_xsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc3_args, + 1, Iclass_xt_iclass_rsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc3_args, + 1, Iclass_xt_iclass_wsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc3_args, + 1, Iclass_xt_iclass_xsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave3_args, + 1, Iclass_xt_iclass_rsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave3_args, + 1, Iclass_xt_iclass_wsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave3_args, + 1, Iclass_xt_iclass_xsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc4_args, + 1, Iclass_xt_iclass_rsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc4_args, + 1, Iclass_xt_iclass_wsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc4_args, + 1, Iclass_xt_iclass_xsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave4_args, + 1, Iclass_xt_iclass_rsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave4_args, + 1, Iclass_xt_iclass_wsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave4_args, + 1, Iclass_xt_iclass_xsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc5_args, + 1, Iclass_xt_iclass_rsr_epc5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc5_args, + 1, Iclass_xt_iclass_wsr_epc5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc5_args, + 1, Iclass_xt_iclass_xsr_epc5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave5_args, + 1, Iclass_xt_iclass_rsr_excsave5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave5_args, + 1, Iclass_xt_iclass_wsr_excsave5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave5_args, + 1, Iclass_xt_iclass_xsr_excsave5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc6_args, + 1, Iclass_xt_iclass_rsr_epc6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc6_args, + 1, Iclass_xt_iclass_wsr_epc6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc6_args, + 1, Iclass_xt_iclass_xsr_epc6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave6_args, + 1, Iclass_xt_iclass_rsr_excsave6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave6_args, + 1, Iclass_xt_iclass_wsr_excsave6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave6_args, + 1, Iclass_xt_iclass_xsr_excsave6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc7_args, + 1, Iclass_xt_iclass_rsr_epc7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc7_args, + 1, Iclass_xt_iclass_wsr_epc7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc7_args, + 1, Iclass_xt_iclass_xsr_epc7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave7_args, + 1, Iclass_xt_iclass_rsr_excsave7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave7_args, + 1, Iclass_xt_iclass_wsr_excsave7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave7_args, + 1, Iclass_xt_iclass_xsr_excsave7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps2_args, + 1, Iclass_xt_iclass_rsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps2_args, + 1, Iclass_xt_iclass_wsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps2_args, + 1, Iclass_xt_iclass_xsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps3_args, + 1, Iclass_xt_iclass_rsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps3_args, + 1, Iclass_xt_iclass_wsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps3_args, + 1, Iclass_xt_iclass_xsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps4_args, + 1, Iclass_xt_iclass_rsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps4_args, + 1, Iclass_xt_iclass_wsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps4_args, + 1, Iclass_xt_iclass_xsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps5_args, + 1, Iclass_xt_iclass_rsr_eps5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps5_args, + 1, Iclass_xt_iclass_wsr_eps5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps5_args, + 1, Iclass_xt_iclass_xsr_eps5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps6_args, + 1, Iclass_xt_iclass_rsr_eps6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps6_args, + 1, Iclass_xt_iclass_wsr_eps6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps6_args, + 1, Iclass_xt_iclass_xsr_eps6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps7_args, + 1, Iclass_xt_iclass_rsr_eps7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps7_args, + 1, Iclass_xt_iclass_wsr_eps7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps7_args, + 1, Iclass_xt_iclass_xsr_eps7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excvaddr_args, + 1, Iclass_xt_iclass_rsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excvaddr_args, + 1, Iclass_xt_iclass_wsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excvaddr_args, + 1, Iclass_xt_iclass_xsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_depc_args, + 1, Iclass_xt_iclass_rsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_depc_args, + 1, Iclass_xt_iclass_wsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_depc_args, + 1, Iclass_xt_iclass_xsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_exccause_args, + 2, Iclass_xt_iclass_rsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_exccause_args, + 1, Iclass_xt_iclass_wsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_exccause_args, + 1, Iclass_xt_iclass_xsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_misc0_args, + 1, Iclass_xt_iclass_rsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_misc0_args, + 1, Iclass_xt_iclass_wsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_misc0_args, + 1, Iclass_xt_iclass_xsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_misc1_args, + 1, Iclass_xt_iclass_rsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_misc1_args, + 1, Iclass_xt_iclass_wsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_misc1_args, + 1, Iclass_xt_iclass_xsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_misc2_args, + 1, Iclass_xt_iclass_rsr_misc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_misc2_args, + 1, Iclass_xt_iclass_wsr_misc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_misc2_args, + 1, Iclass_xt_iclass_xsr_misc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_misc3_args, + 1, Iclass_xt_iclass_rsr_misc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_misc3_args, + 1, Iclass_xt_iclass_wsr_misc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_misc3_args, + 1, Iclass_xt_iclass_xsr_misc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_prid_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_vecbase_args, + 1, Iclass_xt_iclass_rsr_vecbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_vecbase_args, + 1, Iclass_xt_iclass_wsr_vecbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_vecbase_args, + 1, Iclass_xt_iclass_xsr_vecbase_stateArgs, 0, 0 }, + { 3, Iclass_xt_mul16_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_mul32_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_mul32h_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_aa_args, + 1, Iclass_xt_iclass_mac16_aa_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_ad_args, + 1, Iclass_xt_iclass_mac16_ad_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_da_args, + 1, Iclass_xt_iclass_mac16_da_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_dd_args, + 1, Iclass_xt_iclass_mac16_dd_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16a_aa_args, + 1, Iclass_xt_iclass_mac16a_aa_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16a_ad_args, + 1, Iclass_xt_iclass_mac16a_ad_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16a_da_args, + 1, Iclass_xt_iclass_mac16a_da_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16a_dd_args, + 1, Iclass_xt_iclass_mac16a_dd_stateArgs, 0, 0 }, + { 4, Iclass_xt_iclass_mac16al_da_args, + 1, Iclass_xt_iclass_mac16al_da_stateArgs, 0, 0 }, + { 4, Iclass_xt_iclass_mac16al_dd_args, + 1, Iclass_xt_iclass_mac16al_dd_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_l_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_rsr_m0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wsr_m0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_xsr_m0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_rsr_m1_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wsr_m1_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_xsr_m1_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_rsr_m2_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wsr_m2_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_xsr_m2_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_rsr_m3_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wsr_m3_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_xsr_m3_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_acclo_args, + 1, Iclass_xt_iclass_rsr_acclo_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_acclo_args, + 1, Iclass_xt_iclass_wsr_acclo_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_acclo_args, + 1, Iclass_xt_iclass_xsr_acclo_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_acchi_args, + 1, Iclass_xt_iclass_rsr_acchi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_acchi_args, + 1, Iclass_xt_iclass_wsr_acchi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_acchi_args, + 1, Iclass_xt_iclass_xsr_acchi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rfi_args, + 20, Iclass_xt_iclass_rfi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wait_args, + 1, Iclass_xt_iclass_wait_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_interrupt_args, + 1, Iclass_xt_iclass_rsr_interrupt_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intset_args, + 2, Iclass_xt_iclass_wsr_intset_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intclear_args, + 2, Iclass_xt_iclass_wsr_intclear_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_intenable_args, + 1, Iclass_xt_iclass_rsr_intenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intenable_args, + 1, Iclass_xt_iclass_wsr_intenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_intenable_args, + 1, Iclass_xt_iclass_xsr_intenable_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_break_args, + 2, Iclass_xt_iclass_break_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_break_n_args, + 2, Iclass_xt_iclass_break_n_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreaka0_args, + 1, Iclass_xt_iclass_rsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreaka0_args, + 2, Iclass_xt_iclass_wsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreaka0_args, + 2, Iclass_xt_iclass_xsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreakc0_args, + 1, Iclass_xt_iclass_rsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreakc0_args, + 2, Iclass_xt_iclass_wsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreakc0_args, + 2, Iclass_xt_iclass_xsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreaka1_args, + 1, Iclass_xt_iclass_rsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreaka1_args, + 2, Iclass_xt_iclass_wsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreaka1_args, + 2, Iclass_xt_iclass_xsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreakc1_args, + 1, Iclass_xt_iclass_rsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreakc1_args, + 2, Iclass_xt_iclass_wsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreakc1_args, + 2, Iclass_xt_iclass_xsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreaka0_args, + 1, Iclass_xt_iclass_rsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreaka0_args, + 1, Iclass_xt_iclass_wsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreaka0_args, + 1, Iclass_xt_iclass_xsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreaka1_args, + 1, Iclass_xt_iclass_rsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreaka1_args, + 1, Iclass_xt_iclass_wsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreaka1_args, + 1, Iclass_xt_iclass_xsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreakenable_args, + 1, Iclass_xt_iclass_rsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreakenable_args, + 1, Iclass_xt_iclass_wsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreakenable_args, + 1, Iclass_xt_iclass_xsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_debugcause_args, + 2, Iclass_xt_iclass_rsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_debugcause_args, + 2, Iclass_xt_iclass_wsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_debugcause_args, + 2, Iclass_xt_iclass_xsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_icount_args, + 1, Iclass_xt_iclass_rsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_icount_args, + 2, Iclass_xt_iclass_wsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_icount_args, + 2, Iclass_xt_iclass_xsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_icountlevel_args, + 1, Iclass_xt_iclass_rsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_icountlevel_args, + 1, Iclass_xt_iclass_wsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_icountlevel_args, + 1, Iclass_xt_iclass_xsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ddr_args, + 1, Iclass_xt_iclass_rsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ddr_args, + 2, Iclass_xt_iclass_wsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ddr_args, + 2, Iclass_xt_iclass_xsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_lddr32_p_args, + 3, Iclass_xt_iclass_lddr32_p_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_sddr32_p_args, + 2, Iclass_xt_iclass_sddr32_p_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rfdo_args, + 9, Iclass_xt_iclass_rfdo_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfdd */, + 1, Iclass_xt_iclass_rfdd_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_mmid_args, + 1, Iclass_xt_iclass_wsr_mmid_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_bbool1_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bbool4_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bbool8_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bbranch_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bmove_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_RSR_BR_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_WSR_BR_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_XSR_BR_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccount_args, + 1, Iclass_xt_iclass_rsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccount_args, + 2, Iclass_xt_iclass_wsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccount_args, + 2, Iclass_xt_iclass_xsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare0_args, + 1, Iclass_xt_iclass_rsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare0_args, + 2, Iclass_xt_iclass_wsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare0_args, + 2, Iclass_xt_iclass_xsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare1_args, + 1, Iclass_xt_iclass_rsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare1_args, + 2, Iclass_xt_iclass_wsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare1_args, + 2, Iclass_xt_iclass_xsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare2_args, + 1, Iclass_xt_iclass_rsr_ccompare2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare2_args, + 2, Iclass_xt_iclass_wsr_ccompare2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare2_args, + 2, Iclass_xt_iclass_xsr_ccompare2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_idtlb_args, + 1, Iclass_xt_iclass_idtlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_rdtlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wdtlb_args, + 1, Iclass_xt_iclass_wdtlb_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_iitlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_ritlb_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_witlb_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_cpenable_args, + 1, Iclass_xt_iclass_rsr_cpenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_cpenable_args, + 1, Iclass_xt_iclass_wsr_cpenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_cpenable_args, + 1, Iclass_xt_iclass_xsr_cpenable_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_clamp_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_minmax_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_nsa_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_sx_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l32ai_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32ri_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32c1i_args, + 3, Iclass_xt_iclass_s32c1i_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_scompare1_args, + 1, Iclass_xt_iclass_rsr_scompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_scompare1_args, + 1, Iclass_xt_iclass_wsr_scompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_scompare1_args, + 1, Iclass_xt_iclass_xsr_scompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_atomctl_args, + 1, Iclass_xt_iclass_rsr_atomctl_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_atomctl_args, + 2, Iclass_xt_iclass_wsr_atomctl_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_atomctl_args, + 2, Iclass_xt_iclass_xsr_atomctl_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_div_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_rer_args, + 1, Iclass_xt_iclass_rer_stateArgs, 2, Iclass_xt_iclass_rer_intfArgs }, + { 2, Iclass_xt_iclass_wer_args, + 1, Iclass_xt_iclass_wer_stateArgs, 2, Iclass_xt_iclass_wer_intfArgs }, + { 5, Iclass_iclass_F64ITER_args, + 2, Iclass_iclass_F64ITER_stateArgs, 0, 0 }, + { 4, Iclass_iclass_F64RND_args, + 2, Iclass_iclass_F64RND_stateArgs, 0, 0 }, + { 4, Iclass_iclass_F64ADDC_F64SUBC_args, + 1, Iclass_iclass_F64ADDC_F64SUBC_stateArgs, 0, 0 }, + { 2, Iclass_iclass_F64SIG_args, + 0, 0, 0, 0 }, + { 3, Iclass_iclass_F64CMPL_args, + 1, Iclass_iclass_F64CMPL_stateArgs, 0, 0 }, + { 4, Iclass_iclass_F64CMPH_args, + 3, Iclass_iclass_F64CMPH_stateArgs, 0, 0 }, + { 4, Iclass_iclass_F64NORM_args, + 2, Iclass_iclass_F64NORM_stateArgs, 0, 0 }, + { 3, Iclass_iclass_F64SEXP_args, + 0, 0, 0, 0 }, + { 2, Iclass_iclass_RF64R_args, + 1, Iclass_iclass_RF64R_stateArgs, 0, 0 }, + { 3, Iclass_iclass_WF64R_args, + 1, Iclass_iclass_WF64R_stateArgs, 0, 0 }, + { 1, Iclass_rur_f64r_lo_args, + 1, Iclass_rur_f64r_lo_stateArgs, 0, 0 }, + { 1, Iclass_wur_f64r_lo_args, + 1, Iclass_wur_f64r_lo_stateArgs, 0, 0 }, + { 1, Iclass_rur_f64r_hi_args, + 1, Iclass_rur_f64r_hi_stateArgs, 0, 0 }, + { 1, Iclass_wur_f64r_hi_args, + 1, Iclass_wur_f64r_hi_stateArgs, 0, 0 }, + { 1, Iclass_rur_f64s_args, + 1, Iclass_rur_f64s_stateArgs, 0, 0 }, + { 1, Iclass_wur_f64s_args, + 1, Iclass_wur_f64s_stateArgs, 0, 0 }, + { 1, Iclass_rur_fcr_args, + 9, Iclass_rur_fcr_stateArgs, 0, 0 }, + { 1, Iclass_wur_fcr_args, + 9, Iclass_wur_fcr_stateArgs, 0, 0 }, + { 1, Iclass_rur_fsr_args, + 8, Iclass_rur_fsr_stateArgs, 0, 0 }, + { 1, Iclass_wur_fsr_args, + 8, Iclass_wur_fsr_stateArgs, 0, 0 }, + { 1, Iclass_rur_expstate_args, + 1, Iclass_rur_expstate_stateArgs, 0, 0 }, + { 1, Iclass_wur_expstate_args, + 1, Iclass_wur_expstate_stateArgs, 0, 0 }, + { 1, Iclass_iclass_READ_IMPWIRE_args, + 0, 0, 1, Iclass_iclass_READ_IMPWIRE_intfArgs }, + { 1, Iclass_iclass_SETB_EXPSTATE_args, + 1, Iclass_iclass_SETB_EXPSTATE_stateArgs, 0, 0 }, + { 1, Iclass_iclass_CLRB_EXPSTATE_args, + 1, Iclass_iclass_CLRB_EXPSTATE_stateArgs, 0, 0 }, + { 2, Iclass_iclass_WRMSK_EXPSTATE_args, + 1, Iclass_iclass_WRMSK_EXPSTATE_stateArgs, 0, 0 } +}; + +enum xtensa_iclass_id { + ICLASS_LSI, + ICLASS_LSIP, + ICLASS_LSX, + ICLASS_LSXP, + ICLASS_SSI, + ICLASS_SSIP, + ICLASS_SSX, + ICLASS_SSXP, + ICLASS_ABS_S, + ICLASS_NEG_S, + ICLASS_MOV_S, + ICLASS_MOVEQZ_S, + ICLASS_MOVNEZ_S, + ICLASS_MOVLTZ_S, + ICLASS_MOVGEZ_S, + ICLASS_MOVF_S, + ICLASS_MOVT_S, + ICLASS_WFR, + ICLASS_RFR, + ICLASS_ROUND_S, + ICLASS_CEIL_S, + ICLASS_FLOOR_S, + ICLASS_TRUNC_S, + ICLASS_UTRUNC_S, + ICLASS_FLOAT_S, + ICLASS_UFLOAT_S, + ICLASS_UN_S, + ICLASS_ULT_S, + ICLASS_ULE_S, + ICLASS_UEQ_S, + ICLASS_OLT_S, + ICLASS_OLE_S, + ICLASS_OEQ_S, + ICLASS_ADD_S, + ICLASS_SUB_S, + ICLASS_MUL_S, + ICLASS_MADD_S, + ICLASS_MSUB_S, + ICLASS_SQRT0_S, + ICLASS_DIV0_S, + ICLASS_RECIP0_S, + ICLASS_RSQRT0_S, + ICLASS_MADDN_S, + ICLASS_DIVN_S, + ICLASS_CONST_S, + ICLASS_NEXP01_S, + ICLASS_ADDEXP_S, + ICLASS_ADDEXPM_S, + ICLASS_MKDADJ_S, + ICLASS_MKSADJ_S, + ICLASS_xt_iclass_excw, + ICLASS_xt_iclass_rfe, + ICLASS_xt_iclass_rfde, + ICLASS_xt_iclass_syscall, + ICLASS_xt_iclass_call12, + ICLASS_xt_iclass_call8, + ICLASS_xt_iclass_call4, + ICLASS_xt_iclass_callx12, + ICLASS_xt_iclass_callx8, + ICLASS_xt_iclass_callx4, + ICLASS_xt_iclass_entry, + ICLASS_xt_iclass_movsp, + ICLASS_xt_iclass_rotw, + ICLASS_xt_iclass_retw, + ICLASS_xt_iclass_rfwou, + ICLASS_xt_iclass_l32e, + ICLASS_xt_iclass_s32e, + ICLASS_xt_iclass_rsr_windowbase, + ICLASS_xt_iclass_wsr_windowbase, + ICLASS_xt_iclass_xsr_windowbase, + ICLASS_xt_iclass_rsr_windowstart, + ICLASS_xt_iclass_wsr_windowstart, + ICLASS_xt_iclass_xsr_windowstart, + ICLASS_xt_iclass_add_n, + ICLASS_xt_iclass_addi_n, + ICLASS_xt_iclass_bz6, + ICLASS_xt_iclass_ill_n, + ICLASS_xt_iclass_loadi4, + ICLASS_xt_iclass_mov_n, + ICLASS_xt_iclass_movi_n, + ICLASS_xt_iclass_nopn, + ICLASS_xt_iclass_retn, + ICLASS_xt_iclass_storei4, + ICLASS_rur_threadptr, + ICLASS_wur_threadptr, + ICLASS_xt_iclass_addi, + ICLASS_xt_iclass_addmi, + ICLASS_xt_iclass_addsub, + ICLASS_xt_iclass_bit, + ICLASS_xt_iclass_bsi8, + ICLASS_xt_iclass_bsi8b, + ICLASS_xt_iclass_bsi8u, + ICLASS_xt_iclass_bst8, + ICLASS_xt_iclass_bsz12, + ICLASS_xt_iclass_call0, + ICLASS_xt_iclass_callx0, + ICLASS_xt_iclass_exti, + ICLASS_xt_iclass_ill, + ICLASS_xt_iclass_jump, + ICLASS_xt_iclass_jumpx, + ICLASS_xt_iclass_l16ui, + ICLASS_xt_iclass_l16si, + ICLASS_xt_iclass_l32i, + ICLASS_xt_iclass_l32r, + ICLASS_xt_iclass_l8i, + ICLASS_xt_iclass_loop, + ICLASS_xt_iclass_loopz, + ICLASS_xt_iclass_movi, + ICLASS_xt_iclass_movz, + ICLASS_xt_iclass_neg, + ICLASS_xt_iclass_nop, + ICLASS_xt_iclass_return, + ICLASS_xt_iclass_simcall, + ICLASS_xt_iclass_s16i, + ICLASS_xt_iclass_s32i, + ICLASS_xt_iclass_s32nb, + ICLASS_xt_iclass_s8i, + ICLASS_xt_iclass_sar, + ICLASS_xt_iclass_sari, + ICLASS_xt_iclass_shifts, + ICLASS_xt_iclass_shiftst, + ICLASS_xt_iclass_shiftt, + ICLASS_xt_iclass_slli, + ICLASS_xt_iclass_srai, + ICLASS_xt_iclass_srli, + ICLASS_xt_iclass_memw, + ICLASS_xt_iclass_extw, + ICLASS_xt_iclass_isync, + ICLASS_xt_iclass_sync, + ICLASS_xt_iclass_rsil, + ICLASS_xt_iclass_rsr_lend, + ICLASS_xt_iclass_wsr_lend, + ICLASS_xt_iclass_xsr_lend, + ICLASS_xt_iclass_rsr_lcount, + ICLASS_xt_iclass_wsr_lcount, + ICLASS_xt_iclass_xsr_lcount, + ICLASS_xt_iclass_rsr_lbeg, + ICLASS_xt_iclass_wsr_lbeg, + ICLASS_xt_iclass_xsr_lbeg, + ICLASS_xt_iclass_rsr_sar, + ICLASS_xt_iclass_wsr_sar, + ICLASS_xt_iclass_xsr_sar, + ICLASS_xt_iclass_rsr_memctl, + ICLASS_xt_iclass_wsr_memctl, + ICLASS_xt_iclass_xsr_memctl, + ICLASS_xt_iclass_rsr_litbase, + ICLASS_xt_iclass_wsr_litbase, + ICLASS_xt_iclass_xsr_litbase, + ICLASS_xt_iclass_rsr_configid0, + ICLASS_xt_iclass_wsr_configid0, + ICLASS_xt_iclass_rsr_configid1, + ICLASS_xt_iclass_rsr_ps, + ICLASS_xt_iclass_wsr_ps, + ICLASS_xt_iclass_xsr_ps, + ICLASS_xt_iclass_rsr_epc1, + ICLASS_xt_iclass_wsr_epc1, + ICLASS_xt_iclass_xsr_epc1, + ICLASS_xt_iclass_rsr_excsave1, + ICLASS_xt_iclass_wsr_excsave1, + ICLASS_xt_iclass_xsr_excsave1, + ICLASS_xt_iclass_rsr_epc2, + ICLASS_xt_iclass_wsr_epc2, + ICLASS_xt_iclass_xsr_epc2, + ICLASS_xt_iclass_rsr_excsave2, + ICLASS_xt_iclass_wsr_excsave2, + ICLASS_xt_iclass_xsr_excsave2, + ICLASS_xt_iclass_rsr_epc3, + ICLASS_xt_iclass_wsr_epc3, + ICLASS_xt_iclass_xsr_epc3, + ICLASS_xt_iclass_rsr_excsave3, + ICLASS_xt_iclass_wsr_excsave3, + ICLASS_xt_iclass_xsr_excsave3, + ICLASS_xt_iclass_rsr_epc4, + ICLASS_xt_iclass_wsr_epc4, + ICLASS_xt_iclass_xsr_epc4, + ICLASS_xt_iclass_rsr_excsave4, + ICLASS_xt_iclass_wsr_excsave4, + ICLASS_xt_iclass_xsr_excsave4, + ICLASS_xt_iclass_rsr_epc5, + ICLASS_xt_iclass_wsr_epc5, + ICLASS_xt_iclass_xsr_epc5, + ICLASS_xt_iclass_rsr_excsave5, + ICLASS_xt_iclass_wsr_excsave5, + ICLASS_xt_iclass_xsr_excsave5, + ICLASS_xt_iclass_rsr_epc6, + ICLASS_xt_iclass_wsr_epc6, + ICLASS_xt_iclass_xsr_epc6, + ICLASS_xt_iclass_rsr_excsave6, + ICLASS_xt_iclass_wsr_excsave6, + ICLASS_xt_iclass_xsr_excsave6, + ICLASS_xt_iclass_rsr_epc7, + ICLASS_xt_iclass_wsr_epc7, + ICLASS_xt_iclass_xsr_epc7, + ICLASS_xt_iclass_rsr_excsave7, + ICLASS_xt_iclass_wsr_excsave7, + ICLASS_xt_iclass_xsr_excsave7, + ICLASS_xt_iclass_rsr_eps2, + ICLASS_xt_iclass_wsr_eps2, + ICLASS_xt_iclass_xsr_eps2, + ICLASS_xt_iclass_rsr_eps3, + ICLASS_xt_iclass_wsr_eps3, + ICLASS_xt_iclass_xsr_eps3, + ICLASS_xt_iclass_rsr_eps4, + ICLASS_xt_iclass_wsr_eps4, + ICLASS_xt_iclass_xsr_eps4, + ICLASS_xt_iclass_rsr_eps5, + ICLASS_xt_iclass_wsr_eps5, + ICLASS_xt_iclass_xsr_eps5, + ICLASS_xt_iclass_rsr_eps6, + ICLASS_xt_iclass_wsr_eps6, + ICLASS_xt_iclass_xsr_eps6, + ICLASS_xt_iclass_rsr_eps7, + ICLASS_xt_iclass_wsr_eps7, + ICLASS_xt_iclass_xsr_eps7, + ICLASS_xt_iclass_rsr_excvaddr, + ICLASS_xt_iclass_wsr_excvaddr, + ICLASS_xt_iclass_xsr_excvaddr, + ICLASS_xt_iclass_rsr_depc, + ICLASS_xt_iclass_wsr_depc, + ICLASS_xt_iclass_xsr_depc, + ICLASS_xt_iclass_rsr_exccause, + ICLASS_xt_iclass_wsr_exccause, + ICLASS_xt_iclass_xsr_exccause, + ICLASS_xt_iclass_rsr_misc0, + ICLASS_xt_iclass_wsr_misc0, + ICLASS_xt_iclass_xsr_misc0, + ICLASS_xt_iclass_rsr_misc1, + ICLASS_xt_iclass_wsr_misc1, + ICLASS_xt_iclass_xsr_misc1, + ICLASS_xt_iclass_rsr_misc2, + ICLASS_xt_iclass_wsr_misc2, + ICLASS_xt_iclass_xsr_misc2, + ICLASS_xt_iclass_rsr_misc3, + ICLASS_xt_iclass_wsr_misc3, + ICLASS_xt_iclass_xsr_misc3, + ICLASS_xt_iclass_rsr_prid, + ICLASS_xt_iclass_rsr_vecbase, + ICLASS_xt_iclass_wsr_vecbase, + ICLASS_xt_iclass_xsr_vecbase, + ICLASS_xt_mul16, + ICLASS_xt_mul32, + ICLASS_xt_mul32h, + ICLASS_xt_iclass_mac16_aa, + ICLASS_xt_iclass_mac16_ad, + ICLASS_xt_iclass_mac16_da, + ICLASS_xt_iclass_mac16_dd, + ICLASS_xt_iclass_mac16a_aa, + ICLASS_xt_iclass_mac16a_ad, + ICLASS_xt_iclass_mac16a_da, + ICLASS_xt_iclass_mac16a_dd, + ICLASS_xt_iclass_mac16al_da, + ICLASS_xt_iclass_mac16al_dd, + ICLASS_xt_iclass_mac16_l, + ICLASS_xt_iclass_rsr_m0, + ICLASS_xt_iclass_wsr_m0, + ICLASS_xt_iclass_xsr_m0, + ICLASS_xt_iclass_rsr_m1, + ICLASS_xt_iclass_wsr_m1, + ICLASS_xt_iclass_xsr_m1, + ICLASS_xt_iclass_rsr_m2, + ICLASS_xt_iclass_wsr_m2, + ICLASS_xt_iclass_xsr_m2, + ICLASS_xt_iclass_rsr_m3, + ICLASS_xt_iclass_wsr_m3, + ICLASS_xt_iclass_xsr_m3, + ICLASS_xt_iclass_rsr_acclo, + ICLASS_xt_iclass_wsr_acclo, + ICLASS_xt_iclass_xsr_acclo, + ICLASS_xt_iclass_rsr_acchi, + ICLASS_xt_iclass_wsr_acchi, + ICLASS_xt_iclass_xsr_acchi, + ICLASS_xt_iclass_rfi, + ICLASS_xt_iclass_wait, + ICLASS_xt_iclass_rsr_interrupt, + ICLASS_xt_iclass_wsr_intset, + ICLASS_xt_iclass_wsr_intclear, + ICLASS_xt_iclass_rsr_intenable, + ICLASS_xt_iclass_wsr_intenable, + ICLASS_xt_iclass_xsr_intenable, + ICLASS_xt_iclass_break, + ICLASS_xt_iclass_break_n, + ICLASS_xt_iclass_rsr_dbreaka0, + ICLASS_xt_iclass_wsr_dbreaka0, + ICLASS_xt_iclass_xsr_dbreaka0, + ICLASS_xt_iclass_rsr_dbreakc0, + ICLASS_xt_iclass_wsr_dbreakc0, + ICLASS_xt_iclass_xsr_dbreakc0, + ICLASS_xt_iclass_rsr_dbreaka1, + ICLASS_xt_iclass_wsr_dbreaka1, + ICLASS_xt_iclass_xsr_dbreaka1, + ICLASS_xt_iclass_rsr_dbreakc1, + ICLASS_xt_iclass_wsr_dbreakc1, + ICLASS_xt_iclass_xsr_dbreakc1, + ICLASS_xt_iclass_rsr_ibreaka0, + ICLASS_xt_iclass_wsr_ibreaka0, + ICLASS_xt_iclass_xsr_ibreaka0, + ICLASS_xt_iclass_rsr_ibreaka1, + ICLASS_xt_iclass_wsr_ibreaka1, + ICLASS_xt_iclass_xsr_ibreaka1, + ICLASS_xt_iclass_rsr_ibreakenable, + ICLASS_xt_iclass_wsr_ibreakenable, + ICLASS_xt_iclass_xsr_ibreakenable, + ICLASS_xt_iclass_rsr_debugcause, + ICLASS_xt_iclass_wsr_debugcause, + ICLASS_xt_iclass_xsr_debugcause, + ICLASS_xt_iclass_rsr_icount, + ICLASS_xt_iclass_wsr_icount, + ICLASS_xt_iclass_xsr_icount, + ICLASS_xt_iclass_rsr_icountlevel, + ICLASS_xt_iclass_wsr_icountlevel, + ICLASS_xt_iclass_xsr_icountlevel, + ICLASS_xt_iclass_rsr_ddr, + ICLASS_xt_iclass_wsr_ddr, + ICLASS_xt_iclass_xsr_ddr, + ICLASS_xt_iclass_lddr32_p, + ICLASS_xt_iclass_sddr32_p, + ICLASS_xt_iclass_rfdo, + ICLASS_xt_iclass_rfdd, + ICLASS_xt_iclass_wsr_mmid, + ICLASS_xt_iclass_bbool1, + ICLASS_xt_iclass_bbool4, + ICLASS_xt_iclass_bbool8, + ICLASS_xt_iclass_bbranch, + ICLASS_xt_iclass_bmove, + ICLASS_xt_iclass_RSR_BR, + ICLASS_xt_iclass_WSR_BR, + ICLASS_xt_iclass_XSR_BR, + ICLASS_xt_iclass_rsr_ccount, + ICLASS_xt_iclass_wsr_ccount, + ICLASS_xt_iclass_xsr_ccount, + ICLASS_xt_iclass_rsr_ccompare0, + ICLASS_xt_iclass_wsr_ccompare0, + ICLASS_xt_iclass_xsr_ccompare0, + ICLASS_xt_iclass_rsr_ccompare1, + ICLASS_xt_iclass_wsr_ccompare1, + ICLASS_xt_iclass_xsr_ccompare1, + ICLASS_xt_iclass_rsr_ccompare2, + ICLASS_xt_iclass_wsr_ccompare2, + ICLASS_xt_iclass_xsr_ccompare2, + ICLASS_xt_iclass_idtlb, + ICLASS_xt_iclass_rdtlb, + ICLASS_xt_iclass_wdtlb, + ICLASS_xt_iclass_iitlb, + ICLASS_xt_iclass_ritlb, + ICLASS_xt_iclass_witlb, + ICLASS_xt_iclass_rsr_cpenable, + ICLASS_xt_iclass_wsr_cpenable, + ICLASS_xt_iclass_xsr_cpenable, + ICLASS_xt_iclass_clamp, + ICLASS_xt_iclass_minmax, + ICLASS_xt_iclass_nsa, + ICLASS_xt_iclass_sx, + ICLASS_xt_iclass_l32ai, + ICLASS_xt_iclass_s32ri, + ICLASS_xt_iclass_s32c1i, + ICLASS_xt_iclass_rsr_scompare1, + ICLASS_xt_iclass_wsr_scompare1, + ICLASS_xt_iclass_xsr_scompare1, + ICLASS_xt_iclass_rsr_atomctl, + ICLASS_xt_iclass_wsr_atomctl, + ICLASS_xt_iclass_xsr_atomctl, + ICLASS_xt_iclass_div, + ICLASS_xt_iclass_rer, + ICLASS_xt_iclass_wer, + ICLASS_iclass_F64ITER, + ICLASS_iclass_F64RND, + ICLASS_iclass_F64ADDC_F64SUBC, + ICLASS_iclass_F64SIG, + ICLASS_iclass_F64CMPL, + ICLASS_iclass_F64CMPH, + ICLASS_iclass_F64NORM, + ICLASS_iclass_F64SEXP, + ICLASS_iclass_RF64R, + ICLASS_iclass_WF64R, + ICLASS_rur_f64r_lo, + ICLASS_wur_f64r_lo, + ICLASS_rur_f64r_hi, + ICLASS_wur_f64r_hi, + ICLASS_rur_f64s, + ICLASS_wur_f64s, + ICLASS_rur_fcr, + ICLASS_wur_fcr, + ICLASS_rur_fsr, + ICLASS_wur_fsr, + ICLASS_rur_expstate, + ICLASS_wur_expstate, + ICLASS_iclass_READ_IMPWIRE, + ICLASS_iclass_SETB_EXPSTATE, + ICLASS_iclass_CLRB_EXPSTATE, + ICLASS_iclass_WRMSK_EXPSTATE +}; + + +/* Opcode encodings. */ + +static void +Opcode_lsi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3; +} + +static void +Opcode_lsip_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8003; +} + +static void +Opcode_lsx_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x80000; +} + +static void +Opcode_lsxp_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x180000; +} + +static void +Opcode_ssi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4003; +} + +static void +Opcode_ssip_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc003; +} + +static void +Opcode_ssx_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x480000; +} + +static void +Opcode_ssxp_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x580000; +} + +static void +Opcode_abs_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa0010; +} + +static void +Opcode_neg_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa0060; +} + +static void +Opcode_mov_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa0000; +} + +static void +Opcode_moveqz_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8b0000; +} + +static void +Opcode_movnez_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9b0000; +} + +static void +Opcode_movltz_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xab0000; +} + +static void +Opcode_movgez_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xbb0000; +} + +static void +Opcode_movf_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xcb0000; +} + +static void +Opcode_movt_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xdb0000; +} + +static void +Opcode_wfr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa0050; +} + +static void +Opcode_rfr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa0040; +} + +static void +Opcode_round_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8a0000; +} + +static void +Opcode_ceil_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xba0000; +} + +static void +Opcode_floor_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xaa0000; +} + +static void +Opcode_trunc_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9a0000; +} + +static void +Opcode_utrunc_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xea0000; +} + +static void +Opcode_float_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xca0000; +} + +static void +Opcode_ufloat_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xda0000; +} + +static void +Opcode_un_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1b0000; +} + +static void +Opcode_ult_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5b0000; +} + +static void +Opcode_ule_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7b0000; +} + +static void +Opcode_ueq_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b0000; +} + +static void +Opcode_olt_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4b0000; +} + +static void +Opcode_ole_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6b0000; +} + +static void +Opcode_oeq_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2b0000; +} + +static void +Opcode_add_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa0000; +} + +static void +Opcode_sub_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1a0000; +} + +static void +Opcode_mul_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2a0000; +} + +static void +Opcode_madd_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4a0000; +} + +static void +Opcode_msub_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5a0000; +} + +static void +Opcode_sqrt0_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa0090; +} + +static void +Opcode_div0_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa0070; +} + +static void +Opcode_recip0_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa0080; +} + +static void +Opcode_rsqrt0_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa00a0; +} + +static void +Opcode_maddn_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6a0000; +} + +static void +Opcode_divn_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7a0000; +} + +static void +Opcode_const_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa0030; +} + +static void +Opcode_nexp01_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa00b0; +} + +static void +Opcode_addexp_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa00e0; +} + +static void +Opcode_addexpm_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa00f0; +} + +static void +Opcode_mkdadj_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa00d0; +} + +static void +Opcode_mksadj_s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfa00c0; +} + +static void +Opcode_excw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2080; +} + +static void +Opcode_rfe_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3000; +} + +static void +Opcode_rfde_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3200; +} + +static void +Opcode_syscall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5000; +} + +static void +Opcode_call12_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x35; +} + +static void +Opcode_call8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x25; +} + +static void +Opcode_call4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x15; +} + +static void +Opcode_callx12_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf0; +} + +static void +Opcode_callx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe0; +} + +static void +Opcode_callx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd0; +} + +static void +Opcode_entry_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36; +} + +static void +Opcode_movsp_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1000; +} + +static void +Opcode_rotw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x408000; +} + +static void +Opcode_retw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x90; +} + +static void +Opcode_retw_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf01d; +} + +static void +Opcode_rfwo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3400; +} + +static void +Opcode_rfwu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3500; +} + +static void +Opcode_l32e_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x90000; +} + +static void +Opcode_s32e_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x490000; +} + +static void +Opcode_rsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x34800; +} + +static void +Opcode_wsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x134800; +} + +static void +Opcode_xsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x614800; +} + +static void +Opcode_rsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x34900; +} + +static void +Opcode_wsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x134900; +} + +static void +Opcode_xsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x614900; +} + +static void +Opcode_add_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa; +} + +static void +Opcode_addi_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb; +} + +static void +Opcode_beqz_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8c; +} + +static void +Opcode_bnez_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xcc; +} + +static void +Opcode_ill_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf06d; +} + +static void +Opcode_l32i_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8; +} + +static void +Opcode_mov_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd; +} + +static void +Opcode_movi_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc; +} + +static void +Opcode_nop_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf03d; +} + +static void +Opcode_ret_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf00d; +} + +static void +Opcode_s32i_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9; +} + +static void +Opcode_rur_threadptr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe30e70; +} + +static void +Opcode_wur_threadptr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf3e700; +} + +static void +Opcode_addi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc002; +} + +static void +Opcode_addmi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd002; +} + +static void +Opcode_add_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x800000; +} + +static void +Opcode_sub_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc00000; +} + +static void +Opcode_addx2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x900000; +} + +static void +Opcode_addx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa00000; +} + +static void +Opcode_addx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb00000; +} + +static void +Opcode_subx2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd00000; +} + +static void +Opcode_subx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe00000; +} + +static void +Opcode_subx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf00000; +} + +static void +Opcode_and_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x100000; +} + +static void +Opcode_or_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200000; +} + +static void +Opcode_xor_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x300000; +} + +static void +Opcode_beqi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x26; +} + +static void +Opcode_bnei_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x66; +} + +static void +Opcode_bgei_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe6; +} + +static void +Opcode_blti_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa6; +} + +static void +Opcode_bbci_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6007; +} + +static void +Opcode_bbsi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe007; +} + +static void +Opcode_bgeui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf6; +} + +static void +Opcode_bltui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb6; +} + +static void +Opcode_beq_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1007; +} + +static void +Opcode_bne_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9007; +} + +static void +Opcode_bge_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa007; +} + +static void +Opcode_blt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2007; +} + +static void +Opcode_bgeu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb007; +} + +static void +Opcode_bltu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3007; +} + +static void +Opcode_bany_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8007; +} + +static void +Opcode_bnone_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7; +} + +static void +Opcode_ball_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4007; +} + +static void +Opcode_bnall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc007; +} + +static void +Opcode_bbc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5007; +} + +static void +Opcode_bbs_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd007; +} + +static void +Opcode_beqz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x16; +} + +static void +Opcode_bnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x56; +} + +static void +Opcode_bgez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd6; +} + +static void +Opcode_bltz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x96; +} + +static void +Opcode_call0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5; +} + +static void +Opcode_callx0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc0; +} + +static void +Opcode_extui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40000; +} + +static void +Opcode_ill_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0; +} + +static void +Opcode_j_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6; +} + +static void +Opcode_jx_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa0; +} + +static void +Opcode_l16ui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1002; +} + +static void +Opcode_l16si_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9002; +} + +static void +Opcode_l32i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2002; +} + +static void +Opcode_l32r_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1; +} + +static void +Opcode_l8ui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2; +} + +static void +Opcode_loop_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8076; +} + +static void +Opcode_loopnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9076; +} + +static void +Opcode_loopgtz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa076; +} + +static void +Opcode_movi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa002; +} + +static void +Opcode_moveqz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x830000; +} + +static void +Opcode_movnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x930000; +} + +static void +Opcode_movltz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa30000; +} + +static void +Opcode_movgez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb30000; +} + +static void +Opcode_neg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x600000; +} + +static void +Opcode_abs_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x600100; +} + +static void +Opcode_nop_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20f0; +} + +static void +Opcode_ret_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x80; +} + +static void +Opcode_simcall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5100; +} + +static void +Opcode_s16i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5002; +} + +static void +Opcode_s32i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6002; +} + +static void +Opcode_s32nb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x590000; +} + +static void +Opcode_s8i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4002; +} + +static void +Opcode_ssr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x400000; +} + +static void +Opcode_ssl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x401000; +} + +static void +Opcode_ssa8l_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x402000; +} + +static void +Opcode_ssa8b_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x403000; +} + +static void +Opcode_ssai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x404000; +} + +static void +Opcode_sll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa10000; +} + +static void +Opcode_src_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x810000; +} + +static void +Opcode_srl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x910000; +} + +static void +Opcode_sra_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb10000; +} + +static void +Opcode_slli_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x10000; +} + +static void +Opcode_srai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x210000; +} + +static void +Opcode_srli_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x410000; +} + +static void +Opcode_memw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20c0; +} + +static void +Opcode_extw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20d0; +} + +static void +Opcode_isync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2000; +} + +static void +Opcode_rsync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2010; +} + +static void +Opcode_esync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2020; +} + +static void +Opcode_dsync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2030; +} + +static void +Opcode_rsil_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6000; +} + +static void +Opcode_rsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30100; +} + +static void +Opcode_wsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130100; +} + +static void +Opcode_xsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610100; +} + +static void +Opcode_rsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30200; +} + +static void +Opcode_wsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130200; +} + +static void +Opcode_xsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610200; +} + +static void +Opcode_rsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30000; +} + +static void +Opcode_wsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130000; +} + +static void +Opcode_xsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610000; +} + +static void +Opcode_rsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30300; +} + +static void +Opcode_wsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130300; +} + +static void +Opcode_xsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610300; +} + +static void +Opcode_rsr_memctl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36100; +} + +static void +Opcode_wsr_memctl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x136100; +} + +static void +Opcode_xsr_memctl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x616100; +} + +static void +Opcode_rsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30500; +} + +static void +Opcode_wsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130500; +} + +static void +Opcode_xsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610500; +} + +static void +Opcode_rsr_configid0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b000; +} + +static void +Opcode_wsr_configid0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b000; +} + +static void +Opcode_rsr_configid1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d000; +} + +static void +Opcode_rsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e600; +} + +static void +Opcode_wsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e600; +} + +static void +Opcode_xsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e600; +} + +static void +Opcode_rsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b100; +} + +static void +Opcode_wsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b100; +} + +static void +Opcode_xsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b100; +} + +static void +Opcode_rsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d100; +} + +static void +Opcode_wsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d100; +} + +static void +Opcode_xsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d100; +} + +static void +Opcode_rsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b200; +} + +static void +Opcode_wsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b200; +} + +static void +Opcode_xsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b200; +} + +static void +Opcode_rsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d200; +} + +static void +Opcode_wsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d200; +} + +static void +Opcode_xsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d200; +} + +static void +Opcode_rsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b300; +} + +static void +Opcode_wsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b300; +} + +static void +Opcode_xsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b300; +} + +static void +Opcode_rsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d300; +} + +static void +Opcode_wsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d300; +} + +static void +Opcode_xsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d300; +} + +static void +Opcode_rsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b400; +} + +static void +Opcode_wsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b400; +} + +static void +Opcode_xsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b400; +} + +static void +Opcode_rsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d400; +} + +static void +Opcode_wsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d400; +} + +static void +Opcode_xsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d400; +} + +static void +Opcode_rsr_epc5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b500; +} + +static void +Opcode_wsr_epc5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b500; +} + +static void +Opcode_xsr_epc5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b500; +} + +static void +Opcode_rsr_excsave5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d500; +} + +static void +Opcode_wsr_excsave5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d500; +} + +static void +Opcode_xsr_excsave5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d500; +} + +static void +Opcode_rsr_epc6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b600; +} + +static void +Opcode_wsr_epc6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b600; +} + +static void +Opcode_xsr_epc6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b600; +} + +static void +Opcode_rsr_excsave6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d600; +} + +static void +Opcode_wsr_excsave6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d600; +} + +static void +Opcode_xsr_excsave6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d600; +} + +static void +Opcode_rsr_epc7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b700; +} + +static void +Opcode_wsr_epc7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b700; +} + +static void +Opcode_xsr_epc7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b700; +} + +static void +Opcode_rsr_excsave7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d700; +} + +static void +Opcode_wsr_excsave7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d700; +} + +static void +Opcode_xsr_excsave7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d700; +} + +static void +Opcode_rsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c200; +} + +static void +Opcode_wsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c200; +} + +static void +Opcode_xsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c200; +} + +static void +Opcode_rsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c300; +} + +static void +Opcode_wsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c300; +} + +static void +Opcode_xsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c300; +} + +static void +Opcode_rsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c400; +} + +static void +Opcode_wsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c400; +} + +static void +Opcode_xsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c400; +} + +static void +Opcode_rsr_eps5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c500; +} + +static void +Opcode_wsr_eps5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c500; +} + +static void +Opcode_xsr_eps5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c500; +} + +static void +Opcode_rsr_eps6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c600; +} + +static void +Opcode_wsr_eps6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c600; +} + +static void +Opcode_xsr_eps6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c600; +} + +static void +Opcode_rsr_eps7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c700; +} + +static void +Opcode_wsr_eps7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c700; +} + +static void +Opcode_xsr_eps7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c700; +} + +static void +Opcode_rsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ee00; +} + +static void +Opcode_wsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ee00; +} + +static void +Opcode_xsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ee00; +} + +static void +Opcode_rsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c000; +} + +static void +Opcode_wsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c000; +} + +static void +Opcode_xsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c000; +} + +static void +Opcode_rsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e800; +} + +static void +Opcode_wsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e800; +} + +static void +Opcode_xsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e800; +} + +static void +Opcode_rsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f400; +} + +static void +Opcode_wsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f400; +} + +static void +Opcode_xsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f400; +} + +static void +Opcode_rsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f500; +} + +static void +Opcode_wsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f500; +} + +static void +Opcode_xsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f500; +} + +static void +Opcode_rsr_misc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f600; +} + +static void +Opcode_wsr_misc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f600; +} + +static void +Opcode_xsr_misc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f600; +} + +static void +Opcode_rsr_misc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f700; +} + +static void +Opcode_wsr_misc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f700; +} + +static void +Opcode_xsr_misc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f700; +} + +static void +Opcode_rsr_prid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3eb00; +} + +static void +Opcode_rsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e700; +} + +static void +Opcode_wsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e700; +} + +static void +Opcode_xsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e700; +} + +static void +Opcode_mul16u_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc10000; +} + +static void +Opcode_mul16s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd10000; +} + +static void +Opcode_mull_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x820000; +} + +static void +Opcode_muluh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa20000; +} + +static void +Opcode_mulsh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb20000; +} + +static void +Opcode_mul_aa_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x740004; +} + +static void +Opcode_mul_aa_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x750004; +} + +static void +Opcode_mul_aa_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x760004; +} + +static void +Opcode_mul_aa_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x770004; +} + +static void +Opcode_umul_aa_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700004; +} + +static void +Opcode_umul_aa_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x710004; +} + +static void +Opcode_umul_aa_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x720004; +} + +static void +Opcode_umul_aa_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x730004; +} + +static void +Opcode_mul_ad_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x340004; +} + +static void +Opcode_mul_ad_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x350004; +} + +static void +Opcode_mul_ad_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x360004; +} + +static void +Opcode_mul_ad_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x370004; +} + +static void +Opcode_mul_da_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x640004; +} + +static void +Opcode_mul_da_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x650004; +} + +static void +Opcode_mul_da_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x660004; +} + +static void +Opcode_mul_da_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x670004; +} + +static void +Opcode_mul_dd_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x240004; +} + +static void +Opcode_mul_dd_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x250004; +} + +static void +Opcode_mul_dd_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x260004; +} + +static void +Opcode_mul_dd_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x270004; +} + +static void +Opcode_mula_aa_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x780004; +} + +static void +Opcode_mula_aa_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x790004; +} + +static void +Opcode_mula_aa_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7a0004; +} + +static void +Opcode_mula_aa_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7b0004; +} + +static void +Opcode_muls_aa_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7c0004; +} + +static void +Opcode_muls_aa_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7d0004; +} + +static void +Opcode_muls_aa_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7e0004; +} + +static void +Opcode_muls_aa_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7f0004; +} + +static void +Opcode_mula_ad_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x380004; +} + +static void +Opcode_mula_ad_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x390004; +} + +static void +Opcode_mula_ad_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3a0004; +} + +static void +Opcode_mula_ad_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b0004; +} + +static void +Opcode_muls_ad_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c0004; +} + +static void +Opcode_muls_ad_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d0004; +} + +static void +Opcode_muls_ad_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e0004; +} + +static void +Opcode_muls_ad_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f0004; +} + +static void +Opcode_mula_da_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x680004; +} + +static void +Opcode_mula_da_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x690004; +} + +static void +Opcode_mula_da_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6a0004; +} + +static void +Opcode_mula_da_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6b0004; +} + +static void +Opcode_muls_da_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6c0004; +} + +static void +Opcode_muls_da_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6d0004; +} + +static void +Opcode_muls_da_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6e0004; +} + +static void +Opcode_muls_da_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6f0004; +} + +static void +Opcode_mula_dd_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x280004; +} + +static void +Opcode_mula_dd_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x290004; +} + +static void +Opcode_mula_dd_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2a0004; +} + +static void +Opcode_mula_dd_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2b0004; +} + +static void +Opcode_muls_dd_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2c0004; +} + +static void +Opcode_muls_dd_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2d0004; +} + +static void +Opcode_muls_dd_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2e0004; +} + +static void +Opcode_muls_dd_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2f0004; +} + +static void +Opcode_mula_da_ll_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x580004; +} + +static void +Opcode_mula_da_ll_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x480004; +} + +static void +Opcode_mula_da_hl_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x590004; +} + +static void +Opcode_mula_da_hl_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x490004; +} + +static void +Opcode_mula_da_lh_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5a0004; +} + +static void +Opcode_mula_da_lh_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4a0004; +} + +static void +Opcode_mula_da_hh_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5b0004; +} + +static void +Opcode_mula_da_hh_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4b0004; +} + +static void +Opcode_mula_dd_ll_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x180004; +} + +static void +Opcode_mula_dd_ll_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x80004; +} + +static void +Opcode_mula_dd_hl_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x190004; +} + +static void +Opcode_mula_dd_hl_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x90004; +} + +static void +Opcode_mula_dd_lh_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1a0004; +} + +static void +Opcode_mula_dd_lh_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa0004; +} + +static void +Opcode_mula_dd_hh_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1b0004; +} + +static void +Opcode_mula_dd_hh_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb0004; +} + +static void +Opcode_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x900004; +} + +static void +Opcode_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x800004; +} + +static void +Opcode_rsr_m0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x32000; +} + +static void +Opcode_wsr_m0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x132000; +} + +static void +Opcode_xsr_m0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x612000; +} + +static void +Opcode_rsr_m1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x32100; +} + +static void +Opcode_wsr_m1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x132100; +} + +static void +Opcode_xsr_m1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x612100; +} + +static void +Opcode_rsr_m2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x32200; +} + +static void +Opcode_wsr_m2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x132200; +} + +static void +Opcode_xsr_m2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x612200; +} + +static void +Opcode_rsr_m3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x32300; +} + +static void +Opcode_wsr_m3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x132300; +} + +static void +Opcode_xsr_m3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x612300; +} + +static void +Opcode_rsr_acclo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x31000; +} + +static void +Opcode_wsr_acclo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x131000; +} + +static void +Opcode_xsr_acclo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x611000; +} + +static void +Opcode_rsr_acchi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x31100; +} + +static void +Opcode_wsr_acchi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x131100; +} + +static void +Opcode_xsr_acchi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x611100; +} + +static void +Opcode_rfi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3010; +} + +static void +Opcode_waiti_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7000; +} + +static void +Opcode_rsr_interrupt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e200; +} + +static void +Opcode_wsr_intset_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e200; +} + +static void +Opcode_wsr_intclear_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e300; +} + +static void +Opcode_rsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e400; +} + +static void +Opcode_wsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e400; +} + +static void +Opcode_xsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e400; +} + +static void +Opcode_break_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4000; +} + +static void +Opcode_break_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf02d; +} + +static void +Opcode_rsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x39000; +} + +static void +Opcode_wsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x139000; +} + +static void +Opcode_xsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x619000; +} + +static void +Opcode_rsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3a000; +} + +static void +Opcode_wsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13a000; +} + +static void +Opcode_xsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61a000; +} + +static void +Opcode_rsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x39100; +} + +static void +Opcode_wsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x139100; +} + +static void +Opcode_xsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x619100; +} + +static void +Opcode_rsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3a100; +} + +static void +Opcode_wsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13a100; +} + +static void +Opcode_xsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61a100; +} + +static void +Opcode_rsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x38000; +} + +static void +Opcode_wsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x138000; +} + +static void +Opcode_xsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x618000; +} + +static void +Opcode_rsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x38100; +} + +static void +Opcode_wsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x138100; +} + +static void +Opcode_xsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x618100; +} + +static void +Opcode_rsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36000; +} + +static void +Opcode_wsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x136000; +} + +static void +Opcode_xsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x616000; +} + +static void +Opcode_rsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e900; +} + +static void +Opcode_wsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e900; +} + +static void +Opcode_xsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e900; +} + +static void +Opcode_rsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ec00; +} + +static void +Opcode_wsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ec00; +} + +static void +Opcode_xsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ec00; +} + +static void +Opcode_rsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ed00; +} + +static void +Opcode_wsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ed00; +} + +static void +Opcode_xsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ed00; +} + +static void +Opcode_rsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36800; +} + +static void +Opcode_wsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x136800; +} + +static void +Opcode_xsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x616800; +} + +static void +Opcode_lddr32_p_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x70e0; +} + +static void +Opcode_sddr32_p_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x70f0; +} + +static void +Opcode_rfdo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf1e000; +} + +static void +Opcode_rfdd_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf1e010; +} + +static void +Opcode_wsr_mmid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x135900; +} + +static void +Opcode_andb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20000; +} + +static void +Opcode_andbc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x120000; +} + +static void +Opcode_orb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x220000; +} + +static void +Opcode_orbc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x320000; +} + +static void +Opcode_xorb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x420000; +} + +static void +Opcode_any4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8000; +} + +static void +Opcode_all4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9000; +} + +static void +Opcode_any8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa000; +} + +static void +Opcode_all8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb000; +} + +static void +Opcode_bf_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x76; +} + +static void +Opcode_bt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1076; +} + +static void +Opcode_movf_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc30000; +} + +static void +Opcode_movt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd30000; +} + +static void +Opcode_rsr_br_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30400; +} + +static void +Opcode_wsr_br_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130400; +} + +static void +Opcode_xsr_br_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610400; +} + +static void +Opcode_rsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ea00; +} + +static void +Opcode_wsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ea00; +} + +static void +Opcode_xsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ea00; +} + +static void +Opcode_rsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f000; +} + +static void +Opcode_wsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f000; +} + +static void +Opcode_xsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f000; +} + +static void +Opcode_rsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f100; +} + +static void +Opcode_wsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f100; +} + +static void +Opcode_xsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f100; +} + +static void +Opcode_rsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f200; +} + +static void +Opcode_wsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f200; +} + +static void +Opcode_xsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f200; +} + +static void +Opcode_idtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50c000; +} + +static void +Opcode_pdtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50d000; +} + +static void +Opcode_rdtlb0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50b000; +} + +static void +Opcode_rdtlb1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50f000; +} + +static void +Opcode_wdtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50e000; +} + +static void +Opcode_iitlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x504000; +} + +static void +Opcode_pitlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x505000; +} + +static void +Opcode_ritlb0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x503000; +} + +static void +Opcode_ritlb1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x507000; +} + +static void +Opcode_witlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x506000; +} + +static void +Opcode_rsr_cpenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e000; +} + +static void +Opcode_wsr_cpenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e000; +} + +static void +Opcode_xsr_cpenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e000; +} + +static void +Opcode_clamps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x330000; +} + +static void +Opcode_min_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x430000; +} + +static void +Opcode_max_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x530000; +} + +static void +Opcode_minu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x630000; +} + +static void +Opcode_maxu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x730000; +} + +static void +Opcode_nsa_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40e000; +} + +static void +Opcode_nsau_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40f000; +} + +static void +Opcode_sext_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x230000; +} + +static void +Opcode_l32ai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb002; +} + +static void +Opcode_s32ri_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf002; +} + +static void +Opcode_s32c1i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe002; +} + +static void +Opcode_rsr_scompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30c00; +} + +static void +Opcode_wsr_scompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130c00; +} + +static void +Opcode_xsr_scompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610c00; +} + +static void +Opcode_rsr_atomctl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36300; +} + +static void +Opcode_wsr_atomctl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x136300; +} + +static void +Opcode_xsr_atomctl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x616300; +} + +static void +Opcode_quou_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc20000; +} + +static void +Opcode_quos_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd20000; +} + +static void +Opcode_remu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe20000; +} + +static void +Opcode_rems_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf20000; +} + +static void +Opcode_rer_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x406000; +} + +static void +Opcode_wer_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x407000; +} + +static void +Opcode_f64iter_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8e0000; +} + +static void +Opcode_f64rnd_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4e0000; +} + +static void +Opcode_f64addc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfb0000; +} + +static void +Opcode_f64subc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xfb8000; +} + +static void +Opcode_f64sig_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xed000; +} + +static void +Opcode_f64cmpl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xeb0000; +} + +static void +Opcode_f64cmph_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf0000; +} + +static void +Opcode_f64norm_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2e0000; +} + +static void +Opcode_f64sexp_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1e0000; +} + +static void +Opcode_rf64r_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xbce00; +} + +static void +Opcode_wf64r_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xbe000; +} + +static void +Opcode_rur_f64r_lo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe30ea0; +} + +static void +Opcode_wur_f64r_lo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf3ea00; +} + +static void +Opcode_rur_f64r_hi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe30eb0; +} + +static void +Opcode_wur_f64r_hi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf3eb00; +} + +static void +Opcode_rur_f64s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe30ec0; +} + +static void +Opcode_wur_f64s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf3ec00; +} + +static void +Opcode_rur_fcr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe30e80; +} + +static void +Opcode_wur_fcr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf3e800; +} + +static void +Opcode_rur_fsr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe30e90; +} + +static void +Opcode_wur_fsr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf3e900; +} + +static void +Opcode_rur_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe30e60; +} + +static void +Opcode_wur_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf3e600; +} + +static void +Opcode_read_impwire_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe0000; +} + +static void +Opcode_setb_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe1000; +} + +static void +Opcode_clrb_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe1200; +} + +static void +Opcode_wrmsk_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe2000; +} + +static xtensa_opcode_encode_fn Opcode_lsi_encode_fns[] = { + Opcode_lsi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_lsip_encode_fns[] = { + Opcode_lsip_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_lsx_encode_fns[] = { + Opcode_lsx_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_lsxp_encode_fns[] = { + Opcode_lsxp_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssi_encode_fns[] = { + Opcode_ssi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssip_encode_fns[] = { + Opcode_ssip_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssx_encode_fns[] = { + Opcode_ssx_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssxp_encode_fns[] = { + Opcode_ssxp_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_abs_s_encode_fns[] = { + Opcode_abs_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_neg_s_encode_fns[] = { + Opcode_neg_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mov_s_encode_fns[] = { + Opcode_mov_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_moveqz_s_encode_fns[] = { + Opcode_moveqz_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movnez_s_encode_fns[] = { + Opcode_movnez_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movltz_s_encode_fns[] = { + Opcode_movltz_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movgez_s_encode_fns[] = { + Opcode_movgez_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movf_s_encode_fns[] = { + Opcode_movf_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movt_s_encode_fns[] = { + Opcode_movt_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wfr_encode_fns[] = { + Opcode_wfr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfr_encode_fns[] = { + Opcode_rfr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_round_s_encode_fns[] = { + Opcode_round_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ceil_s_encode_fns[] = { + Opcode_ceil_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_floor_s_encode_fns[] = { + Opcode_floor_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_trunc_s_encode_fns[] = { + Opcode_trunc_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_utrunc_s_encode_fns[] = { + Opcode_utrunc_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_float_s_encode_fns[] = { + Opcode_float_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ufloat_s_encode_fns[] = { + Opcode_ufloat_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_un_s_encode_fns[] = { + Opcode_un_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ult_s_encode_fns[] = { + Opcode_ult_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ule_s_encode_fns[] = { + Opcode_ule_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ueq_s_encode_fns[] = { + Opcode_ueq_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_olt_s_encode_fns[] = { + Opcode_olt_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ole_s_encode_fns[] = { + Opcode_ole_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_oeq_s_encode_fns[] = { + Opcode_oeq_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_add_s_encode_fns[] = { + Opcode_add_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sub_s_encode_fns[] = { + Opcode_sub_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_s_encode_fns[] = { + Opcode_mul_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_madd_s_encode_fns[] = { + Opcode_madd_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_msub_s_encode_fns[] = { + Opcode_msub_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sqrt0_s_encode_fns[] = { + Opcode_sqrt0_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_div0_s_encode_fns[] = { + Opcode_div0_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_recip0_s_encode_fns[] = { + Opcode_recip0_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsqrt0_s_encode_fns[] = { + Opcode_rsqrt0_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_maddn_s_encode_fns[] = { + Opcode_maddn_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_divn_s_encode_fns[] = { + Opcode_divn_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_const_s_encode_fns[] = { + Opcode_const_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nexp01_s_encode_fns[] = { + Opcode_nexp01_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addexp_s_encode_fns[] = { + Opcode_addexp_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addexpm_s_encode_fns[] = { + Opcode_addexpm_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mkdadj_s_encode_fns[] = { + Opcode_mkdadj_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mksadj_s_encode_fns[] = { + Opcode_mksadj_s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_excw_encode_fns[] = { + Opcode_excw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfe_encode_fns[] = { + Opcode_rfe_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfde_encode_fns[] = { + Opcode_rfde_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_syscall_encode_fns[] = { + Opcode_syscall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call12_encode_fns[] = { + Opcode_call12_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call8_encode_fns[] = { + Opcode_call8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call4_encode_fns[] = { + Opcode_call4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx12_encode_fns[] = { + Opcode_callx12_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx8_encode_fns[] = { + Opcode_callx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx4_encode_fns[] = { + Opcode_callx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_entry_encode_fns[] = { + Opcode_entry_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movsp_encode_fns[] = { + Opcode_movsp_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rotw_encode_fns[] = { + Opcode_rotw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_retw_encode_fns[] = { + Opcode_retw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_retw_n_encode_fns[] = { + 0, 0, Opcode_retw_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_rfwo_encode_fns[] = { + Opcode_rfwo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfwu_encode_fns[] = { + Opcode_rfwu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32e_encode_fns[] = { + Opcode_l32e_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32e_encode_fns[] = { + Opcode_s32e_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_windowbase_encode_fns[] = { + Opcode_rsr_windowbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_windowbase_encode_fns[] = { + Opcode_wsr_windowbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_windowbase_encode_fns[] = { + Opcode_xsr_windowbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_windowstart_encode_fns[] = { + Opcode_rsr_windowstart_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_windowstart_encode_fns[] = { + Opcode_wsr_windowstart_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_windowstart_encode_fns[] = { + Opcode_xsr_windowstart_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_add_n_encode_fns[] = { + 0, Opcode_add_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addi_n_encode_fns[] = { + 0, Opcode_addi_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqz_n_encode_fns[] = { + 0, 0, Opcode_beqz_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_bnez_n_encode_fns[] = { + 0, 0, Opcode_bnez_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_ill_n_encode_fns[] = { + 0, 0, Opcode_ill_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_l32i_n_encode_fns[] = { + 0, Opcode_l32i_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mov_n_encode_fns[] = { + 0, 0, Opcode_mov_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_movi_n_encode_fns[] = { + 0, 0, Opcode_movi_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_nop_n_encode_fns[] = { + 0, 0, Opcode_nop_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_ret_n_encode_fns[] = { + 0, 0, Opcode_ret_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_s32i_n_encode_fns[] = { + 0, Opcode_s32i_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rur_threadptr_encode_fns[] = { + Opcode_rur_threadptr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wur_threadptr_encode_fns[] = { + Opcode_wur_threadptr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addi_encode_fns[] = { + Opcode_addi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addmi_encode_fns[] = { + Opcode_addmi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_add_encode_fns[] = { + Opcode_add_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sub_encode_fns[] = { + Opcode_sub_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx2_encode_fns[] = { + Opcode_addx2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx4_encode_fns[] = { + Opcode_addx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx8_encode_fns[] = { + Opcode_addx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx2_encode_fns[] = { + Opcode_subx2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx4_encode_fns[] = { + Opcode_subx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx8_encode_fns[] = { + Opcode_subx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_and_encode_fns[] = { + Opcode_and_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_or_encode_fns[] = { + Opcode_or_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xor_encode_fns[] = { + Opcode_xor_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqi_encode_fns[] = { + Opcode_beqi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnei_encode_fns[] = { + Opcode_bnei_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgei_encode_fns[] = { + Opcode_bgei_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_blti_encode_fns[] = { + Opcode_blti_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbci_encode_fns[] = { + Opcode_bbci_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbsi_encode_fns[] = { + Opcode_bbsi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgeui_encode_fns[] = { + Opcode_bgeui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltui_encode_fns[] = { + Opcode_bltui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beq_encode_fns[] = { + Opcode_beq_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bne_encode_fns[] = { + Opcode_bne_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bge_encode_fns[] = { + Opcode_bge_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_blt_encode_fns[] = { + Opcode_blt_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgeu_encode_fns[] = { + Opcode_bgeu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltu_encode_fns[] = { + Opcode_bltu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bany_encode_fns[] = { + Opcode_bany_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnone_encode_fns[] = { + Opcode_bnone_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ball_encode_fns[] = { + Opcode_ball_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnall_encode_fns[] = { + Opcode_bnall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbc_encode_fns[] = { + Opcode_bbc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbs_encode_fns[] = { + Opcode_bbs_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqz_encode_fns[] = { + Opcode_beqz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnez_encode_fns[] = { + Opcode_bnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgez_encode_fns[] = { + Opcode_bgez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltz_encode_fns[] = { + Opcode_bltz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call0_encode_fns[] = { + Opcode_call0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx0_encode_fns[] = { + Opcode_callx0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_extui_encode_fns[] = { + Opcode_extui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ill_encode_fns[] = { + Opcode_ill_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_j_encode_fns[] = { + Opcode_j_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_jx_encode_fns[] = { + Opcode_jx_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l16ui_encode_fns[] = { + Opcode_l16ui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l16si_encode_fns[] = { + Opcode_l16si_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32i_encode_fns[] = { + Opcode_l32i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32r_encode_fns[] = { + Opcode_l32r_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l8ui_encode_fns[] = { + Opcode_l8ui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_loop_encode_fns[] = { + Opcode_loop_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_loopnez_encode_fns[] = { + Opcode_loopnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_loopgtz_encode_fns[] = { + Opcode_loopgtz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movi_encode_fns[] = { + Opcode_movi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_moveqz_encode_fns[] = { + Opcode_moveqz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movnez_encode_fns[] = { + Opcode_movnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movltz_encode_fns[] = { + Opcode_movltz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movgez_encode_fns[] = { + Opcode_movgez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_neg_encode_fns[] = { + Opcode_neg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_abs_encode_fns[] = { + Opcode_abs_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nop_encode_fns[] = { + Opcode_nop_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ret_encode_fns[] = { + Opcode_ret_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_simcall_encode_fns[] = { + Opcode_simcall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s16i_encode_fns[] = { + Opcode_s16i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32i_encode_fns[] = { + Opcode_s32i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32nb_encode_fns[] = { + Opcode_s32nb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s8i_encode_fns[] = { + Opcode_s8i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssr_encode_fns[] = { + Opcode_ssr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssl_encode_fns[] = { + Opcode_ssl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssa8l_encode_fns[] = { + Opcode_ssa8l_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssa8b_encode_fns[] = { + Opcode_ssa8b_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssai_encode_fns[] = { + Opcode_ssai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sll_encode_fns[] = { + Opcode_sll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_src_encode_fns[] = { + Opcode_src_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srl_encode_fns[] = { + Opcode_srl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sra_encode_fns[] = { + Opcode_sra_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_slli_encode_fns[] = { + Opcode_slli_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srai_encode_fns[] = { + Opcode_srai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srli_encode_fns[] = { + Opcode_srli_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_memw_encode_fns[] = { + Opcode_memw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_extw_encode_fns[] = { + Opcode_extw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_isync_encode_fns[] = { + Opcode_isync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsync_encode_fns[] = { + Opcode_rsync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_esync_encode_fns[] = { + Opcode_esync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dsync_encode_fns[] = { + Opcode_dsync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsil_encode_fns[] = { + Opcode_rsil_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_lend_encode_fns[] = { + Opcode_rsr_lend_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_lend_encode_fns[] = { + Opcode_wsr_lend_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_lend_encode_fns[] = { + Opcode_xsr_lend_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_lcount_encode_fns[] = { + Opcode_rsr_lcount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_lcount_encode_fns[] = { + Opcode_wsr_lcount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_lcount_encode_fns[] = { + Opcode_xsr_lcount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_lbeg_encode_fns[] = { + Opcode_rsr_lbeg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_lbeg_encode_fns[] = { + Opcode_wsr_lbeg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_lbeg_encode_fns[] = { + Opcode_xsr_lbeg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_sar_encode_fns[] = { + Opcode_rsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_sar_encode_fns[] = { + Opcode_wsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_sar_encode_fns[] = { + Opcode_xsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_memctl_encode_fns[] = { + Opcode_rsr_memctl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_memctl_encode_fns[] = { + Opcode_wsr_memctl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_memctl_encode_fns[] = { + Opcode_xsr_memctl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_litbase_encode_fns[] = { + Opcode_rsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_litbase_encode_fns[] = { + Opcode_wsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_litbase_encode_fns[] = { + Opcode_xsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_configid0_encode_fns[] = { + Opcode_rsr_configid0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_configid0_encode_fns[] = { + Opcode_wsr_configid0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_configid1_encode_fns[] = { + Opcode_rsr_configid1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ps_encode_fns[] = { + Opcode_rsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ps_encode_fns[] = { + Opcode_wsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ps_encode_fns[] = { + Opcode_xsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc1_encode_fns[] = { + Opcode_rsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc1_encode_fns[] = { + Opcode_wsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc1_encode_fns[] = { + Opcode_xsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave1_encode_fns[] = { + Opcode_rsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave1_encode_fns[] = { + Opcode_wsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave1_encode_fns[] = { + Opcode_xsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc2_encode_fns[] = { + Opcode_rsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc2_encode_fns[] = { + Opcode_wsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc2_encode_fns[] = { + Opcode_xsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave2_encode_fns[] = { + Opcode_rsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave2_encode_fns[] = { + Opcode_wsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave2_encode_fns[] = { + Opcode_xsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc3_encode_fns[] = { + Opcode_rsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc3_encode_fns[] = { + Opcode_wsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc3_encode_fns[] = { + Opcode_xsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave3_encode_fns[] = { + Opcode_rsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave3_encode_fns[] = { + Opcode_wsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave3_encode_fns[] = { + Opcode_xsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc4_encode_fns[] = { + Opcode_rsr_epc4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc4_encode_fns[] = { + Opcode_wsr_epc4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc4_encode_fns[] = { + Opcode_xsr_epc4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave4_encode_fns[] = { + Opcode_rsr_excsave4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave4_encode_fns[] = { + Opcode_wsr_excsave4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave4_encode_fns[] = { + Opcode_xsr_excsave4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc5_encode_fns[] = { + Opcode_rsr_epc5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc5_encode_fns[] = { + Opcode_wsr_epc5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc5_encode_fns[] = { + Opcode_xsr_epc5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave5_encode_fns[] = { + Opcode_rsr_excsave5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave5_encode_fns[] = { + Opcode_wsr_excsave5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave5_encode_fns[] = { + Opcode_xsr_excsave5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc6_encode_fns[] = { + Opcode_rsr_epc6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc6_encode_fns[] = { + Opcode_wsr_epc6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc6_encode_fns[] = { + Opcode_xsr_epc6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave6_encode_fns[] = { + Opcode_rsr_excsave6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave6_encode_fns[] = { + Opcode_wsr_excsave6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave6_encode_fns[] = { + Opcode_xsr_excsave6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc7_encode_fns[] = { + Opcode_rsr_epc7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc7_encode_fns[] = { + Opcode_wsr_epc7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc7_encode_fns[] = { + Opcode_xsr_epc7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave7_encode_fns[] = { + Opcode_rsr_excsave7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave7_encode_fns[] = { + Opcode_wsr_excsave7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave7_encode_fns[] = { + Opcode_xsr_excsave7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps2_encode_fns[] = { + Opcode_rsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps2_encode_fns[] = { + Opcode_wsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps2_encode_fns[] = { + Opcode_xsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps3_encode_fns[] = { + Opcode_rsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps3_encode_fns[] = { + Opcode_wsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps3_encode_fns[] = { + Opcode_xsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps4_encode_fns[] = { + Opcode_rsr_eps4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps4_encode_fns[] = { + Opcode_wsr_eps4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps4_encode_fns[] = { + Opcode_xsr_eps4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps5_encode_fns[] = { + Opcode_rsr_eps5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps5_encode_fns[] = { + Opcode_wsr_eps5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps5_encode_fns[] = { + Opcode_xsr_eps5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps6_encode_fns[] = { + Opcode_rsr_eps6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps6_encode_fns[] = { + Opcode_wsr_eps6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps6_encode_fns[] = { + Opcode_xsr_eps6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps7_encode_fns[] = { + Opcode_rsr_eps7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps7_encode_fns[] = { + Opcode_wsr_eps7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps7_encode_fns[] = { + Opcode_xsr_eps7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excvaddr_encode_fns[] = { + Opcode_rsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excvaddr_encode_fns[] = { + Opcode_wsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excvaddr_encode_fns[] = { + Opcode_xsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_depc_encode_fns[] = { + Opcode_rsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_depc_encode_fns[] = { + Opcode_wsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_depc_encode_fns[] = { + Opcode_xsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_exccause_encode_fns[] = { + Opcode_rsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_exccause_encode_fns[] = { + Opcode_wsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_exccause_encode_fns[] = { + Opcode_xsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_misc0_encode_fns[] = { + Opcode_rsr_misc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_misc0_encode_fns[] = { + Opcode_wsr_misc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_misc0_encode_fns[] = { + Opcode_xsr_misc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_misc1_encode_fns[] = { + Opcode_rsr_misc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_misc1_encode_fns[] = { + Opcode_wsr_misc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_misc1_encode_fns[] = { + Opcode_xsr_misc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_misc2_encode_fns[] = { + Opcode_rsr_misc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_misc2_encode_fns[] = { + Opcode_wsr_misc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_misc2_encode_fns[] = { + Opcode_xsr_misc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_misc3_encode_fns[] = { + Opcode_rsr_misc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_misc3_encode_fns[] = { + Opcode_wsr_misc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_misc3_encode_fns[] = { + Opcode_xsr_misc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_prid_encode_fns[] = { + Opcode_rsr_prid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_vecbase_encode_fns[] = { + Opcode_rsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_vecbase_encode_fns[] = { + Opcode_wsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_vecbase_encode_fns[] = { + Opcode_xsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul16u_encode_fns[] = { + Opcode_mul16u_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul16s_encode_fns[] = { + Opcode_mul16s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mull_encode_fns[] = { + Opcode_mull_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muluh_encode_fns[] = { + Opcode_muluh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mulsh_encode_fns[] = { + Opcode_mulsh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_aa_ll_encode_fns[] = { + Opcode_mul_aa_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_aa_hl_encode_fns[] = { + Opcode_mul_aa_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_aa_lh_encode_fns[] = { + Opcode_mul_aa_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_aa_hh_encode_fns[] = { + Opcode_mul_aa_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_umul_aa_ll_encode_fns[] = { + Opcode_umul_aa_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_umul_aa_hl_encode_fns[] = { + Opcode_umul_aa_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_umul_aa_lh_encode_fns[] = { + Opcode_umul_aa_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_umul_aa_hh_encode_fns[] = { + Opcode_umul_aa_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_ad_ll_encode_fns[] = { + Opcode_mul_ad_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_ad_hl_encode_fns[] = { + Opcode_mul_ad_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_ad_lh_encode_fns[] = { + Opcode_mul_ad_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_ad_hh_encode_fns[] = { + Opcode_mul_ad_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_da_ll_encode_fns[] = { + Opcode_mul_da_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_da_hl_encode_fns[] = { + Opcode_mul_da_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_da_lh_encode_fns[] = { + Opcode_mul_da_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_da_hh_encode_fns[] = { + Opcode_mul_da_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_dd_ll_encode_fns[] = { + Opcode_mul_dd_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_dd_hl_encode_fns[] = { + Opcode_mul_dd_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_dd_lh_encode_fns[] = { + Opcode_mul_dd_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_dd_hh_encode_fns[] = { + Opcode_mul_dd_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_aa_ll_encode_fns[] = { + Opcode_mula_aa_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_aa_hl_encode_fns[] = { + Opcode_mula_aa_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_aa_lh_encode_fns[] = { + Opcode_mula_aa_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_aa_hh_encode_fns[] = { + Opcode_mula_aa_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_aa_ll_encode_fns[] = { + Opcode_muls_aa_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_aa_hl_encode_fns[] = { + Opcode_muls_aa_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_aa_lh_encode_fns[] = { + Opcode_muls_aa_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_aa_hh_encode_fns[] = { + Opcode_muls_aa_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_ad_ll_encode_fns[] = { + Opcode_mula_ad_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_ad_hl_encode_fns[] = { + Opcode_mula_ad_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_ad_lh_encode_fns[] = { + Opcode_mula_ad_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_ad_hh_encode_fns[] = { + Opcode_mula_ad_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_ad_ll_encode_fns[] = { + Opcode_muls_ad_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_ad_hl_encode_fns[] = { + Opcode_muls_ad_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_ad_lh_encode_fns[] = { + Opcode_muls_ad_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_ad_hh_encode_fns[] = { + Opcode_muls_ad_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_ll_encode_fns[] = { + Opcode_mula_da_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hl_encode_fns[] = { + Opcode_mula_da_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_lh_encode_fns[] = { + Opcode_mula_da_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hh_encode_fns[] = { + Opcode_mula_da_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_da_ll_encode_fns[] = { + Opcode_muls_da_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_da_hl_encode_fns[] = { + Opcode_muls_da_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_da_lh_encode_fns[] = { + Opcode_muls_da_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_da_hh_encode_fns[] = { + Opcode_muls_da_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_ll_encode_fns[] = { + Opcode_mula_dd_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hl_encode_fns[] = { + Opcode_mula_dd_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_lh_encode_fns[] = { + Opcode_mula_dd_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hh_encode_fns[] = { + Opcode_mula_dd_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_dd_ll_encode_fns[] = { + Opcode_muls_dd_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_dd_hl_encode_fns[] = { + Opcode_muls_dd_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_dd_lh_encode_fns[] = { + Opcode_muls_dd_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_dd_hh_encode_fns[] = { + Opcode_muls_dd_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_ll_lddec_encode_fns[] = { + Opcode_mula_da_ll_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_ll_ldinc_encode_fns[] = { + Opcode_mula_da_ll_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hl_lddec_encode_fns[] = { + Opcode_mula_da_hl_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hl_ldinc_encode_fns[] = { + Opcode_mula_da_hl_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_lh_lddec_encode_fns[] = { + Opcode_mula_da_lh_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_lh_ldinc_encode_fns[] = { + Opcode_mula_da_lh_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hh_lddec_encode_fns[] = { + Opcode_mula_da_hh_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hh_ldinc_encode_fns[] = { + Opcode_mula_da_hh_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_ll_lddec_encode_fns[] = { + Opcode_mula_dd_ll_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_ll_ldinc_encode_fns[] = { + Opcode_mula_dd_ll_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hl_lddec_encode_fns[] = { + Opcode_mula_dd_hl_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hl_ldinc_encode_fns[] = { + Opcode_mula_dd_hl_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_lh_lddec_encode_fns[] = { + Opcode_mula_dd_lh_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_lh_ldinc_encode_fns[] = { + Opcode_mula_dd_lh_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hh_lddec_encode_fns[] = { + Opcode_mula_dd_hh_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hh_ldinc_encode_fns[] = { + Opcode_mula_dd_hh_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_lddec_encode_fns[] = { + Opcode_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ldinc_encode_fns[] = { + Opcode_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_m0_encode_fns[] = { + Opcode_rsr_m0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_m0_encode_fns[] = { + Opcode_wsr_m0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_m0_encode_fns[] = { + Opcode_xsr_m0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_m1_encode_fns[] = { + Opcode_rsr_m1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_m1_encode_fns[] = { + Opcode_wsr_m1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_m1_encode_fns[] = { + Opcode_xsr_m1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_m2_encode_fns[] = { + Opcode_rsr_m2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_m2_encode_fns[] = { + Opcode_wsr_m2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_m2_encode_fns[] = { + Opcode_xsr_m2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_m3_encode_fns[] = { + Opcode_rsr_m3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_m3_encode_fns[] = { + Opcode_wsr_m3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_m3_encode_fns[] = { + Opcode_xsr_m3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_acclo_encode_fns[] = { + Opcode_rsr_acclo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_acclo_encode_fns[] = { + Opcode_wsr_acclo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_acclo_encode_fns[] = { + Opcode_xsr_acclo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_acchi_encode_fns[] = { + Opcode_rsr_acchi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_acchi_encode_fns[] = { + Opcode_wsr_acchi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_acchi_encode_fns[] = { + Opcode_xsr_acchi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfi_encode_fns[] = { + Opcode_rfi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_waiti_encode_fns[] = { + Opcode_waiti_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_interrupt_encode_fns[] = { + Opcode_rsr_interrupt_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intset_encode_fns[] = { + Opcode_wsr_intset_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intclear_encode_fns[] = { + Opcode_wsr_intclear_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_intenable_encode_fns[] = { + Opcode_rsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intenable_encode_fns[] = { + Opcode_wsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_intenable_encode_fns[] = { + Opcode_xsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_break_encode_fns[] = { + Opcode_break_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_break_n_encode_fns[] = { + 0, 0, Opcode_break_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreaka0_encode_fns[] = { + Opcode_rsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreaka0_encode_fns[] = { + Opcode_wsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreaka0_encode_fns[] = { + Opcode_xsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreakc0_encode_fns[] = { + Opcode_rsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreakc0_encode_fns[] = { + Opcode_wsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreakc0_encode_fns[] = { + Opcode_xsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreaka1_encode_fns[] = { + Opcode_rsr_dbreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreaka1_encode_fns[] = { + Opcode_wsr_dbreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreaka1_encode_fns[] = { + Opcode_xsr_dbreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreakc1_encode_fns[] = { + Opcode_rsr_dbreakc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreakc1_encode_fns[] = { + Opcode_wsr_dbreakc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreakc1_encode_fns[] = { + Opcode_xsr_dbreakc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreaka0_encode_fns[] = { + Opcode_rsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreaka0_encode_fns[] = { + Opcode_wsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreaka0_encode_fns[] = { + Opcode_xsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreaka1_encode_fns[] = { + Opcode_rsr_ibreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreaka1_encode_fns[] = { + Opcode_wsr_ibreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreaka1_encode_fns[] = { + Opcode_xsr_ibreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreakenable_encode_fns[] = { + Opcode_rsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreakenable_encode_fns[] = { + Opcode_wsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreakenable_encode_fns[] = { + Opcode_xsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_debugcause_encode_fns[] = { + Opcode_rsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_debugcause_encode_fns[] = { + Opcode_wsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_debugcause_encode_fns[] = { + Opcode_xsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_icount_encode_fns[] = { + Opcode_rsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_icount_encode_fns[] = { + Opcode_wsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_icount_encode_fns[] = { + Opcode_xsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_icountlevel_encode_fns[] = { + Opcode_rsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_icountlevel_encode_fns[] = { + Opcode_wsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_icountlevel_encode_fns[] = { + Opcode_xsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ddr_encode_fns[] = { + Opcode_rsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ddr_encode_fns[] = { + Opcode_wsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ddr_encode_fns[] = { + Opcode_xsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_lddr32_p_encode_fns[] = { + Opcode_lddr32_p_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sddr32_p_encode_fns[] = { + Opcode_sddr32_p_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfdo_encode_fns[] = { + Opcode_rfdo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfdd_encode_fns[] = { + Opcode_rfdd_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_mmid_encode_fns[] = { + Opcode_wsr_mmid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_andb_encode_fns[] = { + Opcode_andb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_andbc_encode_fns[] = { + Opcode_andbc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_orb_encode_fns[] = { + Opcode_orb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_orbc_encode_fns[] = { + Opcode_orbc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xorb_encode_fns[] = { + Opcode_xorb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_any4_encode_fns[] = { + Opcode_any4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_all4_encode_fns[] = { + Opcode_all4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_any8_encode_fns[] = { + Opcode_any8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_all8_encode_fns[] = { + Opcode_all8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bf_encode_fns[] = { + Opcode_bf_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bt_encode_fns[] = { + Opcode_bt_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movf_encode_fns[] = { + Opcode_movf_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movt_encode_fns[] = { + Opcode_movt_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_br_encode_fns[] = { + Opcode_rsr_br_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_br_encode_fns[] = { + Opcode_wsr_br_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_br_encode_fns[] = { + Opcode_xsr_br_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccount_encode_fns[] = { + Opcode_rsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccount_encode_fns[] = { + Opcode_wsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccount_encode_fns[] = { + Opcode_xsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccompare0_encode_fns[] = { + Opcode_rsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccompare0_encode_fns[] = { + Opcode_wsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccompare0_encode_fns[] = { + Opcode_xsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccompare1_encode_fns[] = { + Opcode_rsr_ccompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccompare1_encode_fns[] = { + Opcode_wsr_ccompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccompare1_encode_fns[] = { + Opcode_xsr_ccompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccompare2_encode_fns[] = { + Opcode_rsr_ccompare2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccompare2_encode_fns[] = { + Opcode_wsr_ccompare2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccompare2_encode_fns[] = { + Opcode_xsr_ccompare2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_idtlb_encode_fns[] = { + Opcode_idtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_pdtlb_encode_fns[] = { + Opcode_pdtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rdtlb0_encode_fns[] = { + Opcode_rdtlb0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rdtlb1_encode_fns[] = { + Opcode_rdtlb1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wdtlb_encode_fns[] = { + Opcode_wdtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_iitlb_encode_fns[] = { + Opcode_iitlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_pitlb_encode_fns[] = { + Opcode_pitlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ritlb0_encode_fns[] = { + Opcode_ritlb0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ritlb1_encode_fns[] = { + Opcode_ritlb1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_witlb_encode_fns[] = { + Opcode_witlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_cpenable_encode_fns[] = { + Opcode_rsr_cpenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_cpenable_encode_fns[] = { + Opcode_wsr_cpenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_cpenable_encode_fns[] = { + Opcode_xsr_cpenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_clamps_encode_fns[] = { + Opcode_clamps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_min_encode_fns[] = { + Opcode_min_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_max_encode_fns[] = { + Opcode_max_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_minu_encode_fns[] = { + Opcode_minu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_maxu_encode_fns[] = { + Opcode_maxu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nsa_encode_fns[] = { + Opcode_nsa_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nsau_encode_fns[] = { + Opcode_nsau_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sext_encode_fns[] = { + Opcode_sext_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32ai_encode_fns[] = { + Opcode_l32ai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32ri_encode_fns[] = { + Opcode_s32ri_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32c1i_encode_fns[] = { + Opcode_s32c1i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_scompare1_encode_fns[] = { + Opcode_rsr_scompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_scompare1_encode_fns[] = { + Opcode_wsr_scompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_scompare1_encode_fns[] = { + Opcode_xsr_scompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_atomctl_encode_fns[] = { + Opcode_rsr_atomctl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_atomctl_encode_fns[] = { + Opcode_wsr_atomctl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_atomctl_encode_fns[] = { + Opcode_xsr_atomctl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_quou_encode_fns[] = { + Opcode_quou_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_quos_encode_fns[] = { + Opcode_quos_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_remu_encode_fns[] = { + Opcode_remu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rems_encode_fns[] = { + Opcode_rems_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rer_encode_fns[] = { + Opcode_rer_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wer_encode_fns[] = { + Opcode_wer_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_f64iter_encode_fns[] = { + Opcode_f64iter_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_f64rnd_encode_fns[] = { + Opcode_f64rnd_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_f64addc_encode_fns[] = { + Opcode_f64addc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_f64subc_encode_fns[] = { + Opcode_f64subc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_f64sig_encode_fns[] = { + Opcode_f64sig_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_f64cmpl_encode_fns[] = { + Opcode_f64cmpl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_f64cmph_encode_fns[] = { + Opcode_f64cmph_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_f64norm_encode_fns[] = { + Opcode_f64norm_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_f64sexp_encode_fns[] = { + Opcode_f64sexp_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rf64r_encode_fns[] = { + Opcode_rf64r_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wf64r_encode_fns[] = { + Opcode_wf64r_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rur_f64r_lo_encode_fns[] = { + Opcode_rur_f64r_lo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wur_f64r_lo_encode_fns[] = { + Opcode_wur_f64r_lo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rur_f64r_hi_encode_fns[] = { + Opcode_rur_f64r_hi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wur_f64r_hi_encode_fns[] = { + Opcode_wur_f64r_hi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rur_f64s_encode_fns[] = { + Opcode_rur_f64s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wur_f64s_encode_fns[] = { + Opcode_wur_f64s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rur_fcr_encode_fns[] = { + Opcode_rur_fcr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wur_fcr_encode_fns[] = { + Opcode_wur_fcr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rur_fsr_encode_fns[] = { + Opcode_rur_fsr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wur_fsr_encode_fns[] = { + Opcode_wur_fsr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rur_expstate_encode_fns[] = { + Opcode_rur_expstate_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wur_expstate_encode_fns[] = { + Opcode_wur_expstate_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_read_impwire_encode_fns[] = { + Opcode_read_impwire_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_setb_expstate_encode_fns[] = { + Opcode_setb_expstate_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_clrb_expstate_encode_fns[] = { + Opcode_clrb_expstate_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wrmsk_expstate_encode_fns[] = { + Opcode_wrmsk_expstate_Slot_inst_encode, 0, 0 +}; + + +uint32 *bypass_entry(__attribute__((unused)) int i); +uint32 *bypass_entry(__attribute__((unused)) int i) { + return 0; +} + + +/* Opcode table. */ + +static xtensa_opcode_internal opcodes[] = { + { "lsi", ICLASS_LSI, + 0, + Opcode_lsi_encode_fns, 0, 0 }, + { "lsip", ICLASS_LSIP, + 0, + Opcode_lsip_encode_fns, 0, 0 }, + { "lsx", ICLASS_LSX, + 0, + Opcode_lsx_encode_fns, 0, 0 }, + { "lsxp", ICLASS_LSXP, + 0, + Opcode_lsxp_encode_fns, 0, 0 }, + { "ssi", ICLASS_SSI, + 0, + Opcode_ssi_encode_fns, 0, 0 }, + { "ssip", ICLASS_SSIP, + 0, + Opcode_ssip_encode_fns, 0, 0 }, + { "ssx", ICLASS_SSX, + 0, + Opcode_ssx_encode_fns, 0, 0 }, + { "ssxp", ICLASS_SSXP, + 0, + Opcode_ssxp_encode_fns, 0, 0 }, + { "abs.s", ICLASS_ABS_S, + 0, + Opcode_abs_s_encode_fns, 0, 0 }, + { "neg.s", ICLASS_NEG_S, + 0, + Opcode_neg_s_encode_fns, 0, 0 }, + { "mov.s", ICLASS_MOV_S, + 0, + Opcode_mov_s_encode_fns, 0, 0 }, + { "moveqz.s", ICLASS_MOVEQZ_S, + 0, + Opcode_moveqz_s_encode_fns, 0, 0 }, + { "movnez.s", ICLASS_MOVNEZ_S, + 0, + Opcode_movnez_s_encode_fns, 0, 0 }, + { "movltz.s", ICLASS_MOVLTZ_S, + 0, + Opcode_movltz_s_encode_fns, 0, 0 }, + { "movgez.s", ICLASS_MOVGEZ_S, + 0, + Opcode_movgez_s_encode_fns, 0, 0 }, + { "movf.s", ICLASS_MOVF_S, + 0, + Opcode_movf_s_encode_fns, 0, 0 }, + { "movt.s", ICLASS_MOVT_S, + 0, + Opcode_movt_s_encode_fns, 0, 0 }, + { "wfr", ICLASS_WFR, + 0, + Opcode_wfr_encode_fns, 0, 0 }, + { "rfr", ICLASS_RFR, + 0, + Opcode_rfr_encode_fns, 0, 0 }, + { "round.s", ICLASS_ROUND_S, + 0, + Opcode_round_s_encode_fns, 0, 0 }, + { "ceil.s", ICLASS_CEIL_S, + 0, + Opcode_ceil_s_encode_fns, 0, 0 }, + { "floor.s", ICLASS_FLOOR_S, + 0, + Opcode_floor_s_encode_fns, 0, 0 }, + { "trunc.s", ICLASS_TRUNC_S, + 0, + Opcode_trunc_s_encode_fns, 0, 0 }, + { "utrunc.s", ICLASS_UTRUNC_S, + 0, + Opcode_utrunc_s_encode_fns, 0, 0 }, + { "float.s", ICLASS_FLOAT_S, + 0, + Opcode_float_s_encode_fns, 0, 0 }, + { "ufloat.s", ICLASS_UFLOAT_S, + 0, + Opcode_ufloat_s_encode_fns, 0, 0 }, + { "un.s", ICLASS_UN_S, + 0, + Opcode_un_s_encode_fns, 0, 0 }, + { "ult.s", ICLASS_ULT_S, + 0, + Opcode_ult_s_encode_fns, 0, 0 }, + { "ule.s", ICLASS_ULE_S, + 0, + Opcode_ule_s_encode_fns, 0, 0 }, + { "ueq.s", ICLASS_UEQ_S, + 0, + Opcode_ueq_s_encode_fns, 0, 0 }, + { "olt.s", ICLASS_OLT_S, + 0, + Opcode_olt_s_encode_fns, 0, 0 }, + { "ole.s", ICLASS_OLE_S, + 0, + Opcode_ole_s_encode_fns, 0, 0 }, + { "oeq.s", ICLASS_OEQ_S, + 0, + Opcode_oeq_s_encode_fns, 0, 0 }, + { "add.s", ICLASS_ADD_S, + 0, + Opcode_add_s_encode_fns, 0, 0 }, + { "sub.s", ICLASS_SUB_S, + 0, + Opcode_sub_s_encode_fns, 0, 0 }, + { "mul.s", ICLASS_MUL_S, + 0, + Opcode_mul_s_encode_fns, 0, 0 }, + { "madd.s", ICLASS_MADD_S, + 0, + Opcode_madd_s_encode_fns, 0, 0 }, + { "msub.s", ICLASS_MSUB_S, + 0, + Opcode_msub_s_encode_fns, 0, 0 }, + { "sqrt0.s", ICLASS_SQRT0_S, + 0, + Opcode_sqrt0_s_encode_fns, 0, 0 }, + { "div0.s", ICLASS_DIV0_S, + 0, + Opcode_div0_s_encode_fns, 0, 0 }, + { "recip0.s", ICLASS_RECIP0_S, + 0, + Opcode_recip0_s_encode_fns, 0, 0 }, + { "rsqrt0.s", ICLASS_RSQRT0_S, + 0, + Opcode_rsqrt0_s_encode_fns, 0, 0 }, + { "maddn.s", ICLASS_MADDN_S, + 0, + Opcode_maddn_s_encode_fns, 0, 0 }, + { "divn.s", ICLASS_DIVN_S, + 0, + Opcode_divn_s_encode_fns, 0, 0 }, + { "const.s", ICLASS_CONST_S, + 0, + Opcode_const_s_encode_fns, 0, 0 }, + { "nexp01.s", ICLASS_NEXP01_S, + 0, + Opcode_nexp01_s_encode_fns, 0, 0 }, + { "addexp.s", ICLASS_ADDEXP_S, + 0, + Opcode_addexp_s_encode_fns, 0, 0 }, + { "addexpm.s", ICLASS_ADDEXPM_S, + 0, + Opcode_addexpm_s_encode_fns, 0, 0 }, + { "mkdadj.s", ICLASS_MKDADJ_S, + 0, + Opcode_mkdadj_s_encode_fns, 0, 0 }, + { "mksadj.s", ICLASS_MKSADJ_S, + 0, + Opcode_mksadj_s_encode_fns, 0, 0 }, + { "excw", ICLASS_xt_iclass_excw, + 0, + Opcode_excw_encode_fns, 0, 0 }, + { "rfe", ICLASS_xt_iclass_rfe, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfe_encode_fns, 0, 0 }, + { "rfde", ICLASS_xt_iclass_rfde, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfde_encode_fns, 0, 0 }, + { "syscall", ICLASS_xt_iclass_syscall, + 0, + Opcode_syscall_encode_fns, 0, 0 }, + { "call12", ICLASS_xt_iclass_call12, + XTENSA_OPCODE_IS_CALL, + Opcode_call12_encode_fns, 0, 0 }, + { "call8", ICLASS_xt_iclass_call8, + XTENSA_OPCODE_IS_CALL, + Opcode_call8_encode_fns, 0, 0 }, + { "call4", ICLASS_xt_iclass_call4, + XTENSA_OPCODE_IS_CALL, + Opcode_call4_encode_fns, 0, 0 }, + { "callx12", ICLASS_xt_iclass_callx12, + XTENSA_OPCODE_IS_CALL, + Opcode_callx12_encode_fns, 0, 0 }, + { "callx8", ICLASS_xt_iclass_callx8, + XTENSA_OPCODE_IS_CALL, + Opcode_callx8_encode_fns, 0, 0 }, + { "callx4", ICLASS_xt_iclass_callx4, + XTENSA_OPCODE_IS_CALL, + Opcode_callx4_encode_fns, 0, 0 }, + { "entry", ICLASS_xt_iclass_entry, + 0, + Opcode_entry_encode_fns, 0, 0 }, + { "movsp", ICLASS_xt_iclass_movsp, + 0, + Opcode_movsp_encode_fns, 0, 0 }, + { "rotw", ICLASS_xt_iclass_rotw, + 0, + Opcode_rotw_encode_fns, 0, 0 }, + { "retw", ICLASS_xt_iclass_retw, + XTENSA_OPCODE_IS_JUMP, + Opcode_retw_encode_fns, 0, 0 }, + { "retw.n", ICLASS_xt_iclass_retw, + XTENSA_OPCODE_IS_JUMP, + Opcode_retw_n_encode_fns, 0, 0 }, + { "rfwo", ICLASS_xt_iclass_rfwou, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfwo_encode_fns, 0, 0 }, + { "rfwu", ICLASS_xt_iclass_rfwou, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfwu_encode_fns, 0, 0 }, + { "l32e", ICLASS_xt_iclass_l32e, + 0, + Opcode_l32e_encode_fns, 0, 0 }, + { "s32e", ICLASS_xt_iclass_s32e, + 0, + Opcode_s32e_encode_fns, 0, 0 }, + { "rsr.windowbase", ICLASS_xt_iclass_rsr_windowbase, + 0, + Opcode_rsr_windowbase_encode_fns, 0, 0 }, + { "wsr.windowbase", ICLASS_xt_iclass_wsr_windowbase, + 0, + Opcode_wsr_windowbase_encode_fns, 0, 0 }, + { "xsr.windowbase", ICLASS_xt_iclass_xsr_windowbase, + 0, + Opcode_xsr_windowbase_encode_fns, 0, 0 }, + { "rsr.windowstart", ICLASS_xt_iclass_rsr_windowstart, + 0, + Opcode_rsr_windowstart_encode_fns, 0, 0 }, + { "wsr.windowstart", ICLASS_xt_iclass_wsr_windowstart, + 0, + Opcode_wsr_windowstart_encode_fns, 0, 0 }, + { "xsr.windowstart", ICLASS_xt_iclass_xsr_windowstart, + 0, + Opcode_xsr_windowstart_encode_fns, 0, 0 }, + { "add.n", ICLASS_xt_iclass_add_n, + 0, + Opcode_add_n_encode_fns, 0, 0 }, + { "addi.n", ICLASS_xt_iclass_addi_n, + 0, + Opcode_addi_n_encode_fns, 0, 0 }, + { "beqz.n", ICLASS_xt_iclass_bz6, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqz_n_encode_fns, 0, 0 }, + { "bnez.n", ICLASS_xt_iclass_bz6, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnez_n_encode_fns, 0, 0 }, + { "ill.n", ICLASS_xt_iclass_ill_n, + 0, + Opcode_ill_n_encode_fns, 0, 0 }, + { "l32i.n", ICLASS_xt_iclass_loadi4, + 0, + Opcode_l32i_n_encode_fns, 0, 0 }, + { "mov.n", ICLASS_xt_iclass_mov_n, + 0, + Opcode_mov_n_encode_fns, 0, 0 }, + { "movi.n", ICLASS_xt_iclass_movi_n, + 0, + Opcode_movi_n_encode_fns, 0, 0 }, + { "nop.n", ICLASS_xt_iclass_nopn, + 0, + Opcode_nop_n_encode_fns, 0, 0 }, + { "ret.n", ICLASS_xt_iclass_retn, + XTENSA_OPCODE_IS_JUMP, + Opcode_ret_n_encode_fns, 0, 0 }, + { "s32i.n", ICLASS_xt_iclass_storei4, + 0, + Opcode_s32i_n_encode_fns, 0, 0 }, + { "rur.threadptr", ICLASS_rur_threadptr, + 0, + Opcode_rur_threadptr_encode_fns, 0, 0 }, + { "wur.threadptr", ICLASS_wur_threadptr, + 0, + Opcode_wur_threadptr_encode_fns, 0, 0 }, + { "addi", ICLASS_xt_iclass_addi, + 0, + Opcode_addi_encode_fns, 0, 0 }, + { "addmi", ICLASS_xt_iclass_addmi, + 0, + Opcode_addmi_encode_fns, 0, 0 }, + { "add", ICLASS_xt_iclass_addsub, + 0, + Opcode_add_encode_fns, 0, 0 }, + { "sub", ICLASS_xt_iclass_addsub, + 0, + Opcode_sub_encode_fns, 0, 0 }, + { "addx2", ICLASS_xt_iclass_addsub, + 0, + Opcode_addx2_encode_fns, 0, 0 }, + { "addx4", ICLASS_xt_iclass_addsub, + 0, + Opcode_addx4_encode_fns, 0, 0 }, + { "addx8", ICLASS_xt_iclass_addsub, + 0, + Opcode_addx8_encode_fns, 0, 0 }, + { "subx2", ICLASS_xt_iclass_addsub, + 0, + Opcode_subx2_encode_fns, 0, 0 }, + { "subx4", ICLASS_xt_iclass_addsub, + 0, + Opcode_subx4_encode_fns, 0, 0 }, + { "subx8", ICLASS_xt_iclass_addsub, + 0, + Opcode_subx8_encode_fns, 0, 0 }, + { "and", ICLASS_xt_iclass_bit, + 0, + Opcode_and_encode_fns, 0, 0 }, + { "or", ICLASS_xt_iclass_bit, + 0, + Opcode_or_encode_fns, 0, 0 }, + { "xor", ICLASS_xt_iclass_bit, + 0, + Opcode_xor_encode_fns, 0, 0 }, + { "beqi", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqi_encode_fns, 0, 0 }, + { "bnei", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnei_encode_fns, 0, 0 }, + { "bgei", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgei_encode_fns, 0, 0 }, + { "blti", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_blti_encode_fns, 0, 0 }, + { "bbci", ICLASS_xt_iclass_bsi8b, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbci_encode_fns, 0, 0 }, + { "bbsi", ICLASS_xt_iclass_bsi8b, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbsi_encode_fns, 0, 0 }, + { "bgeui", ICLASS_xt_iclass_bsi8u, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgeui_encode_fns, 0, 0 }, + { "bltui", ICLASS_xt_iclass_bsi8u, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltui_encode_fns, 0, 0 }, + { "beq", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beq_encode_fns, 0, 0 }, + { "bne", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bne_encode_fns, 0, 0 }, + { "bge", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bge_encode_fns, 0, 0 }, + { "blt", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_blt_encode_fns, 0, 0 }, + { "bgeu", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgeu_encode_fns, 0, 0 }, + { "bltu", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltu_encode_fns, 0, 0 }, + { "bany", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bany_encode_fns, 0, 0 }, + { "bnone", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnone_encode_fns, 0, 0 }, + { "ball", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_ball_encode_fns, 0, 0 }, + { "bnall", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnall_encode_fns, 0, 0 }, + { "bbc", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbc_encode_fns, 0, 0 }, + { "bbs", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbs_encode_fns, 0, 0 }, + { "beqz", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqz_encode_fns, 0, 0 }, + { "bnez", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnez_encode_fns, 0, 0 }, + { "bgez", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgez_encode_fns, 0, 0 }, + { "bltz", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltz_encode_fns, 0, 0 }, + { "call0", ICLASS_xt_iclass_call0, + XTENSA_OPCODE_IS_CALL, + Opcode_call0_encode_fns, 0, 0 }, + { "callx0", ICLASS_xt_iclass_callx0, + XTENSA_OPCODE_IS_CALL, + Opcode_callx0_encode_fns, 0, 0 }, + { "extui", ICLASS_xt_iclass_exti, + 0, + Opcode_extui_encode_fns, 0, 0 }, + { "ill", ICLASS_xt_iclass_ill, + 0, + Opcode_ill_encode_fns, 0, 0 }, + { "j", ICLASS_xt_iclass_jump, + XTENSA_OPCODE_IS_JUMP, + Opcode_j_encode_fns, 0, 0 }, + { "jx", ICLASS_xt_iclass_jumpx, + XTENSA_OPCODE_IS_JUMP, + Opcode_jx_encode_fns, 0, 0 }, + { "l16ui", ICLASS_xt_iclass_l16ui, + 0, + Opcode_l16ui_encode_fns, 0, 0 }, + { "l16si", ICLASS_xt_iclass_l16si, + 0, + Opcode_l16si_encode_fns, 0, 0 }, + { "l32i", ICLASS_xt_iclass_l32i, + 0, + Opcode_l32i_encode_fns, 0, 0 }, + { "l32r", ICLASS_xt_iclass_l32r, + 0, + Opcode_l32r_encode_fns, 0, 0 }, + { "l8ui", ICLASS_xt_iclass_l8i, + 0, + Opcode_l8ui_encode_fns, 0, 0 }, + { "loop", ICLASS_xt_iclass_loop, + XTENSA_OPCODE_IS_LOOP, + Opcode_loop_encode_fns, 0, 0 }, + { "loopnez", ICLASS_xt_iclass_loopz, + XTENSA_OPCODE_IS_LOOP, + Opcode_loopnez_encode_fns, 0, 0 }, + { "loopgtz", ICLASS_xt_iclass_loopz, + XTENSA_OPCODE_IS_LOOP, + Opcode_loopgtz_encode_fns, 0, 0 }, + { "movi", ICLASS_xt_iclass_movi, + 0, + Opcode_movi_encode_fns, 0, 0 }, + { "moveqz", ICLASS_xt_iclass_movz, + 0, + Opcode_moveqz_encode_fns, 0, 0 }, + { "movnez", ICLASS_xt_iclass_movz, + 0, + Opcode_movnez_encode_fns, 0, 0 }, + { "movltz", ICLASS_xt_iclass_movz, + 0, + Opcode_movltz_encode_fns, 0, 0 }, + { "movgez", ICLASS_xt_iclass_movz, + 0, + Opcode_movgez_encode_fns, 0, 0 }, + { "neg", ICLASS_xt_iclass_neg, + 0, + Opcode_neg_encode_fns, 0, 0 }, + { "abs", ICLASS_xt_iclass_neg, + 0, + Opcode_abs_encode_fns, 0, 0 }, + { "nop", ICLASS_xt_iclass_nop, + 0, + Opcode_nop_encode_fns, 0, 0 }, + { "ret", ICLASS_xt_iclass_return, + XTENSA_OPCODE_IS_JUMP, + Opcode_ret_encode_fns, 0, 0 }, + { "simcall", ICLASS_xt_iclass_simcall, + 0, + Opcode_simcall_encode_fns, 0, 0 }, + { "s16i", ICLASS_xt_iclass_s16i, + 0, + Opcode_s16i_encode_fns, 0, 0 }, + { "s32i", ICLASS_xt_iclass_s32i, + 0, + Opcode_s32i_encode_fns, 0, 0 }, + { "s32nb", ICLASS_xt_iclass_s32nb, + 0, + Opcode_s32nb_encode_fns, 0, 0 }, + { "s8i", ICLASS_xt_iclass_s8i, + 0, + Opcode_s8i_encode_fns, 0, 0 }, + { "ssr", ICLASS_xt_iclass_sar, + 0, + Opcode_ssr_encode_fns, 0, 0 }, + { "ssl", ICLASS_xt_iclass_sar, + 0, + Opcode_ssl_encode_fns, 0, 0 }, + { "ssa8l", ICLASS_xt_iclass_sar, + 0, + Opcode_ssa8l_encode_fns, 0, 0 }, + { "ssa8b", ICLASS_xt_iclass_sar, + 0, + Opcode_ssa8b_encode_fns, 0, 0 }, + { "ssai", ICLASS_xt_iclass_sari, + 0, + Opcode_ssai_encode_fns, 0, 0 }, + { "sll", ICLASS_xt_iclass_shifts, + 0, + Opcode_sll_encode_fns, 0, 0 }, + { "src", ICLASS_xt_iclass_shiftst, + 0, + Opcode_src_encode_fns, 0, 0 }, + { "srl", ICLASS_xt_iclass_shiftt, + 0, + Opcode_srl_encode_fns, 0, 0 }, + { "sra", ICLASS_xt_iclass_shiftt, + 0, + Opcode_sra_encode_fns, 0, 0 }, + { "slli", ICLASS_xt_iclass_slli, + 0, + Opcode_slli_encode_fns, 0, 0 }, + { "srai", ICLASS_xt_iclass_srai, + 0, + Opcode_srai_encode_fns, 0, 0 }, + { "srli", ICLASS_xt_iclass_srli, + 0, + Opcode_srli_encode_fns, 0, 0 }, + { "memw", ICLASS_xt_iclass_memw, + 0, + Opcode_memw_encode_fns, 0, 0 }, + { "extw", ICLASS_xt_iclass_extw, + 0, + Opcode_extw_encode_fns, 0, 0 }, + { "isync", ICLASS_xt_iclass_isync, + 0, + Opcode_isync_encode_fns, 0, 0 }, + { "rsync", ICLASS_xt_iclass_sync, + 0, + Opcode_rsync_encode_fns, 0, 0 }, + { "esync", ICLASS_xt_iclass_sync, + 0, + Opcode_esync_encode_fns, 0, 0 }, + { "dsync", ICLASS_xt_iclass_sync, + 0, + Opcode_dsync_encode_fns, 0, 0 }, + { "rsil", ICLASS_xt_iclass_rsil, + 0, + Opcode_rsil_encode_fns, 0, 0 }, + { "rsr.lend", ICLASS_xt_iclass_rsr_lend, + 0, + Opcode_rsr_lend_encode_fns, 0, 0 }, + { "wsr.lend", ICLASS_xt_iclass_wsr_lend, + 0, + Opcode_wsr_lend_encode_fns, 0, 0 }, + { "xsr.lend", ICLASS_xt_iclass_xsr_lend, + 0, + Opcode_xsr_lend_encode_fns, 0, 0 }, + { "rsr.lcount", ICLASS_xt_iclass_rsr_lcount, + 0, + Opcode_rsr_lcount_encode_fns, 0, 0 }, + { "wsr.lcount", ICLASS_xt_iclass_wsr_lcount, + 0, + Opcode_wsr_lcount_encode_fns, 0, 0 }, + { "xsr.lcount", ICLASS_xt_iclass_xsr_lcount, + 0, + Opcode_xsr_lcount_encode_fns, 0, 0 }, + { "rsr.lbeg", ICLASS_xt_iclass_rsr_lbeg, + 0, + Opcode_rsr_lbeg_encode_fns, 0, 0 }, + { "wsr.lbeg", ICLASS_xt_iclass_wsr_lbeg, + 0, + Opcode_wsr_lbeg_encode_fns, 0, 0 }, + { "xsr.lbeg", ICLASS_xt_iclass_xsr_lbeg, + 0, + Opcode_xsr_lbeg_encode_fns, 0, 0 }, + { "rsr.sar", ICLASS_xt_iclass_rsr_sar, + 0, + Opcode_rsr_sar_encode_fns, 0, 0 }, + { "wsr.sar", ICLASS_xt_iclass_wsr_sar, + 0, + Opcode_wsr_sar_encode_fns, 0, 0 }, + { "xsr.sar", ICLASS_xt_iclass_xsr_sar, + 0, + Opcode_xsr_sar_encode_fns, 0, 0 }, + { "rsr.memctl", ICLASS_xt_iclass_rsr_memctl, + 0, + Opcode_rsr_memctl_encode_fns, 0, 0 }, + { "wsr.memctl", ICLASS_xt_iclass_wsr_memctl, + 0, + Opcode_wsr_memctl_encode_fns, 0, 0 }, + { "xsr.memctl", ICLASS_xt_iclass_xsr_memctl, + 0, + Opcode_xsr_memctl_encode_fns, 0, 0 }, + { "rsr.litbase", ICLASS_xt_iclass_rsr_litbase, + 0, + Opcode_rsr_litbase_encode_fns, 0, 0 }, + { "wsr.litbase", ICLASS_xt_iclass_wsr_litbase, + 0, + Opcode_wsr_litbase_encode_fns, 0, 0 }, + { "xsr.litbase", ICLASS_xt_iclass_xsr_litbase, + 0, + Opcode_xsr_litbase_encode_fns, 0, 0 }, + { "rsr.configid0", ICLASS_xt_iclass_rsr_configid0, + 0, + Opcode_rsr_configid0_encode_fns, 0, 0 }, + { "wsr.configid0", ICLASS_xt_iclass_wsr_configid0, + 0, + Opcode_wsr_configid0_encode_fns, 0, 0 }, + { "rsr.configid1", ICLASS_xt_iclass_rsr_configid1, + 0, + Opcode_rsr_configid1_encode_fns, 0, 0 }, + { "rsr.ps", ICLASS_xt_iclass_rsr_ps, + 0, + Opcode_rsr_ps_encode_fns, 0, 0 }, + { "wsr.ps", ICLASS_xt_iclass_wsr_ps, + 0, + Opcode_wsr_ps_encode_fns, 0, 0 }, + { "xsr.ps", ICLASS_xt_iclass_xsr_ps, + 0, + Opcode_xsr_ps_encode_fns, 0, 0 }, + { "rsr.epc1", ICLASS_xt_iclass_rsr_epc1, + 0, + Opcode_rsr_epc1_encode_fns, 0, 0 }, + { "wsr.epc1", ICLASS_xt_iclass_wsr_epc1, + 0, + Opcode_wsr_epc1_encode_fns, 0, 0 }, + { "xsr.epc1", ICLASS_xt_iclass_xsr_epc1, + 0, + Opcode_xsr_epc1_encode_fns, 0, 0 }, + { "rsr.excsave1", ICLASS_xt_iclass_rsr_excsave1, + 0, + Opcode_rsr_excsave1_encode_fns, 0, 0 }, + { "wsr.excsave1", ICLASS_xt_iclass_wsr_excsave1, + 0, + Opcode_wsr_excsave1_encode_fns, 0, 0 }, + { "xsr.excsave1", ICLASS_xt_iclass_xsr_excsave1, + 0, + Opcode_xsr_excsave1_encode_fns, 0, 0 }, + { "rsr.epc2", ICLASS_xt_iclass_rsr_epc2, + 0, + Opcode_rsr_epc2_encode_fns, 0, 0 }, + { "wsr.epc2", ICLASS_xt_iclass_wsr_epc2, + 0, + Opcode_wsr_epc2_encode_fns, 0, 0 }, + { "xsr.epc2", ICLASS_xt_iclass_xsr_epc2, + 0, + Opcode_xsr_epc2_encode_fns, 0, 0 }, + { "rsr.excsave2", ICLASS_xt_iclass_rsr_excsave2, + 0, + Opcode_rsr_excsave2_encode_fns, 0, 0 }, + { "wsr.excsave2", ICLASS_xt_iclass_wsr_excsave2, + 0, + Opcode_wsr_excsave2_encode_fns, 0, 0 }, + { "xsr.excsave2", ICLASS_xt_iclass_xsr_excsave2, + 0, + Opcode_xsr_excsave2_encode_fns, 0, 0 }, + { "rsr.epc3", ICLASS_xt_iclass_rsr_epc3, + 0, + Opcode_rsr_epc3_encode_fns, 0, 0 }, + { "wsr.epc3", ICLASS_xt_iclass_wsr_epc3, + 0, + Opcode_wsr_epc3_encode_fns, 0, 0 }, + { "xsr.epc3", ICLASS_xt_iclass_xsr_epc3, + 0, + Opcode_xsr_epc3_encode_fns, 0, 0 }, + { "rsr.excsave3", ICLASS_xt_iclass_rsr_excsave3, + 0, + Opcode_rsr_excsave3_encode_fns, 0, 0 }, + { "wsr.excsave3", ICLASS_xt_iclass_wsr_excsave3, + 0, + Opcode_wsr_excsave3_encode_fns, 0, 0 }, + { "xsr.excsave3", ICLASS_xt_iclass_xsr_excsave3, + 0, + Opcode_xsr_excsave3_encode_fns, 0, 0 }, + { "rsr.epc4", ICLASS_xt_iclass_rsr_epc4, + 0, + Opcode_rsr_epc4_encode_fns, 0, 0 }, + { "wsr.epc4", ICLASS_xt_iclass_wsr_epc4, + 0, + Opcode_wsr_epc4_encode_fns, 0, 0 }, + { "xsr.epc4", ICLASS_xt_iclass_xsr_epc4, + 0, + Opcode_xsr_epc4_encode_fns, 0, 0 }, + { "rsr.excsave4", ICLASS_xt_iclass_rsr_excsave4, + 0, + Opcode_rsr_excsave4_encode_fns, 0, 0 }, + { "wsr.excsave4", ICLASS_xt_iclass_wsr_excsave4, + 0, + Opcode_wsr_excsave4_encode_fns, 0, 0 }, + { "xsr.excsave4", ICLASS_xt_iclass_xsr_excsave4, + 0, + Opcode_xsr_excsave4_encode_fns, 0, 0 }, + { "rsr.epc5", ICLASS_xt_iclass_rsr_epc5, + 0, + Opcode_rsr_epc5_encode_fns, 0, 0 }, + { "wsr.epc5", ICLASS_xt_iclass_wsr_epc5, + 0, + Opcode_wsr_epc5_encode_fns, 0, 0 }, + { "xsr.epc5", ICLASS_xt_iclass_xsr_epc5, + 0, + Opcode_xsr_epc5_encode_fns, 0, 0 }, + { "rsr.excsave5", ICLASS_xt_iclass_rsr_excsave5, + 0, + Opcode_rsr_excsave5_encode_fns, 0, 0 }, + { "wsr.excsave5", ICLASS_xt_iclass_wsr_excsave5, + 0, + Opcode_wsr_excsave5_encode_fns, 0, 0 }, + { "xsr.excsave5", ICLASS_xt_iclass_xsr_excsave5, + 0, + Opcode_xsr_excsave5_encode_fns, 0, 0 }, + { "rsr.epc6", ICLASS_xt_iclass_rsr_epc6, + 0, + Opcode_rsr_epc6_encode_fns, 0, 0 }, + { "wsr.epc6", ICLASS_xt_iclass_wsr_epc6, + 0, + Opcode_wsr_epc6_encode_fns, 0, 0 }, + { "xsr.epc6", ICLASS_xt_iclass_xsr_epc6, + 0, + Opcode_xsr_epc6_encode_fns, 0, 0 }, + { "rsr.excsave6", ICLASS_xt_iclass_rsr_excsave6, + 0, + Opcode_rsr_excsave6_encode_fns, 0, 0 }, + { "wsr.excsave6", ICLASS_xt_iclass_wsr_excsave6, + 0, + Opcode_wsr_excsave6_encode_fns, 0, 0 }, + { "xsr.excsave6", ICLASS_xt_iclass_xsr_excsave6, + 0, + Opcode_xsr_excsave6_encode_fns, 0, 0 }, + { "rsr.epc7", ICLASS_xt_iclass_rsr_epc7, + 0, + Opcode_rsr_epc7_encode_fns, 0, 0 }, + { "wsr.epc7", ICLASS_xt_iclass_wsr_epc7, + 0, + Opcode_wsr_epc7_encode_fns, 0, 0 }, + { "xsr.epc7", ICLASS_xt_iclass_xsr_epc7, + 0, + Opcode_xsr_epc7_encode_fns, 0, 0 }, + { "rsr.excsave7", ICLASS_xt_iclass_rsr_excsave7, + 0, + Opcode_rsr_excsave7_encode_fns, 0, 0 }, + { "wsr.excsave7", ICLASS_xt_iclass_wsr_excsave7, + 0, + Opcode_wsr_excsave7_encode_fns, 0, 0 }, + { "xsr.excsave7", ICLASS_xt_iclass_xsr_excsave7, + 0, + Opcode_xsr_excsave7_encode_fns, 0, 0 }, + { "rsr.eps2", ICLASS_xt_iclass_rsr_eps2, + 0, + Opcode_rsr_eps2_encode_fns, 0, 0 }, + { "wsr.eps2", ICLASS_xt_iclass_wsr_eps2, + 0, + Opcode_wsr_eps2_encode_fns, 0, 0 }, + { "xsr.eps2", ICLASS_xt_iclass_xsr_eps2, + 0, + Opcode_xsr_eps2_encode_fns, 0, 0 }, + { "rsr.eps3", ICLASS_xt_iclass_rsr_eps3, + 0, + Opcode_rsr_eps3_encode_fns, 0, 0 }, + { "wsr.eps3", ICLASS_xt_iclass_wsr_eps3, + 0, + Opcode_wsr_eps3_encode_fns, 0, 0 }, + { "xsr.eps3", ICLASS_xt_iclass_xsr_eps3, + 0, + Opcode_xsr_eps3_encode_fns, 0, 0 }, + { "rsr.eps4", ICLASS_xt_iclass_rsr_eps4, + 0, + Opcode_rsr_eps4_encode_fns, 0, 0 }, + { "wsr.eps4", ICLASS_xt_iclass_wsr_eps4, + 0, + Opcode_wsr_eps4_encode_fns, 0, 0 }, + { "xsr.eps4", ICLASS_xt_iclass_xsr_eps4, + 0, + Opcode_xsr_eps4_encode_fns, 0, 0 }, + { "rsr.eps5", ICLASS_xt_iclass_rsr_eps5, + 0, + Opcode_rsr_eps5_encode_fns, 0, 0 }, + { "wsr.eps5", ICLASS_xt_iclass_wsr_eps5, + 0, + Opcode_wsr_eps5_encode_fns, 0, 0 }, + { "xsr.eps5", ICLASS_xt_iclass_xsr_eps5, + 0, + Opcode_xsr_eps5_encode_fns, 0, 0 }, + { "rsr.eps6", ICLASS_xt_iclass_rsr_eps6, + 0, + Opcode_rsr_eps6_encode_fns, 0, 0 }, + { "wsr.eps6", ICLASS_xt_iclass_wsr_eps6, + 0, + Opcode_wsr_eps6_encode_fns, 0, 0 }, + { "xsr.eps6", ICLASS_xt_iclass_xsr_eps6, + 0, + Opcode_xsr_eps6_encode_fns, 0, 0 }, + { "rsr.eps7", ICLASS_xt_iclass_rsr_eps7, + 0, + Opcode_rsr_eps7_encode_fns, 0, 0 }, + { "wsr.eps7", ICLASS_xt_iclass_wsr_eps7, + 0, + Opcode_wsr_eps7_encode_fns, 0, 0 }, + { "xsr.eps7", ICLASS_xt_iclass_xsr_eps7, + 0, + Opcode_xsr_eps7_encode_fns, 0, 0 }, + { "rsr.excvaddr", ICLASS_xt_iclass_rsr_excvaddr, + 0, + Opcode_rsr_excvaddr_encode_fns, 0, 0 }, + { "wsr.excvaddr", ICLASS_xt_iclass_wsr_excvaddr, + 0, + Opcode_wsr_excvaddr_encode_fns, 0, 0 }, + { "xsr.excvaddr", ICLASS_xt_iclass_xsr_excvaddr, + 0, + Opcode_xsr_excvaddr_encode_fns, 0, 0 }, + { "rsr.depc", ICLASS_xt_iclass_rsr_depc, + 0, + Opcode_rsr_depc_encode_fns, 0, 0 }, + { "wsr.depc", ICLASS_xt_iclass_wsr_depc, + 0, + Opcode_wsr_depc_encode_fns, 0, 0 }, + { "xsr.depc", ICLASS_xt_iclass_xsr_depc, + 0, + Opcode_xsr_depc_encode_fns, 0, 0 }, + { "rsr.exccause", ICLASS_xt_iclass_rsr_exccause, + 0, + Opcode_rsr_exccause_encode_fns, 0, 0 }, + { "wsr.exccause", ICLASS_xt_iclass_wsr_exccause, + 0, + Opcode_wsr_exccause_encode_fns, 0, 0 }, + { "xsr.exccause", ICLASS_xt_iclass_xsr_exccause, + 0, + Opcode_xsr_exccause_encode_fns, 0, 0 }, + { "rsr.misc0", ICLASS_xt_iclass_rsr_misc0, + 0, + Opcode_rsr_misc0_encode_fns, 0, 0 }, + { "wsr.misc0", ICLASS_xt_iclass_wsr_misc0, + 0, + Opcode_wsr_misc0_encode_fns, 0, 0 }, + { "xsr.misc0", ICLASS_xt_iclass_xsr_misc0, + 0, + Opcode_xsr_misc0_encode_fns, 0, 0 }, + { "rsr.misc1", ICLASS_xt_iclass_rsr_misc1, + 0, + Opcode_rsr_misc1_encode_fns, 0, 0 }, + { "wsr.misc1", ICLASS_xt_iclass_wsr_misc1, + 0, + Opcode_wsr_misc1_encode_fns, 0, 0 }, + { "xsr.misc1", ICLASS_xt_iclass_xsr_misc1, + 0, + Opcode_xsr_misc1_encode_fns, 0, 0 }, + { "rsr.misc2", ICLASS_xt_iclass_rsr_misc2, + 0, + Opcode_rsr_misc2_encode_fns, 0, 0 }, + { "wsr.misc2", ICLASS_xt_iclass_wsr_misc2, + 0, + Opcode_wsr_misc2_encode_fns, 0, 0 }, + { "xsr.misc2", ICLASS_xt_iclass_xsr_misc2, + 0, + Opcode_xsr_misc2_encode_fns, 0, 0 }, + { "rsr.misc3", ICLASS_xt_iclass_rsr_misc3, + 0, + Opcode_rsr_misc3_encode_fns, 0, 0 }, + { "wsr.misc3", ICLASS_xt_iclass_wsr_misc3, + 0, + Opcode_wsr_misc3_encode_fns, 0, 0 }, + { "xsr.misc3", ICLASS_xt_iclass_xsr_misc3, + 0, + Opcode_xsr_misc3_encode_fns, 0, 0 }, + { "rsr.prid", ICLASS_xt_iclass_rsr_prid, + 0, + Opcode_rsr_prid_encode_fns, 0, 0 }, + { "rsr.vecbase", ICLASS_xt_iclass_rsr_vecbase, + 0, + Opcode_rsr_vecbase_encode_fns, 0, 0 }, + { "wsr.vecbase", ICLASS_xt_iclass_wsr_vecbase, + 0, + Opcode_wsr_vecbase_encode_fns, 0, 0 }, + { "xsr.vecbase", ICLASS_xt_iclass_xsr_vecbase, + 0, + Opcode_xsr_vecbase_encode_fns, 0, 0 }, + { "mul16u", ICLASS_xt_mul16, + 0, + Opcode_mul16u_encode_fns, 0, 0 }, + { "mul16s", ICLASS_xt_mul16, + 0, + Opcode_mul16s_encode_fns, 0, 0 }, + { "mull", ICLASS_xt_mul32, + 0, + Opcode_mull_encode_fns, 0, 0 }, + { "muluh", ICLASS_xt_mul32h, + 0, + Opcode_muluh_encode_fns, 0, 0 }, + { "mulsh", ICLASS_xt_mul32h, + 0, + Opcode_mulsh_encode_fns, 0, 0 }, + { "mul.aa.ll", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_mul_aa_ll_encode_fns, 0, 0 }, + { "mul.aa.hl", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_mul_aa_hl_encode_fns, 0, 0 }, + { "mul.aa.lh", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_mul_aa_lh_encode_fns, 0, 0 }, + { "mul.aa.hh", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_mul_aa_hh_encode_fns, 0, 0 }, + { "umul.aa.ll", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_umul_aa_ll_encode_fns, 0, 0 }, + { "umul.aa.hl", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_umul_aa_hl_encode_fns, 0, 0 }, + { "umul.aa.lh", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_umul_aa_lh_encode_fns, 0, 0 }, + { "umul.aa.hh", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_umul_aa_hh_encode_fns, 0, 0 }, + { "mul.ad.ll", ICLASS_xt_iclass_mac16_ad, + 0, + Opcode_mul_ad_ll_encode_fns, 0, 0 }, + { "mul.ad.hl", ICLASS_xt_iclass_mac16_ad, + 0, + Opcode_mul_ad_hl_encode_fns, 0, 0 }, + { "mul.ad.lh", ICLASS_xt_iclass_mac16_ad, + 0, + Opcode_mul_ad_lh_encode_fns, 0, 0 }, + { "mul.ad.hh", ICLASS_xt_iclass_mac16_ad, + 0, + Opcode_mul_ad_hh_encode_fns, 0, 0 }, + { "mul.da.ll", ICLASS_xt_iclass_mac16_da, + 0, + Opcode_mul_da_ll_encode_fns, 0, 0 }, + { "mul.da.hl", ICLASS_xt_iclass_mac16_da, + 0, + Opcode_mul_da_hl_encode_fns, 0, 0 }, + { "mul.da.lh", ICLASS_xt_iclass_mac16_da, + 0, + Opcode_mul_da_lh_encode_fns, 0, 0 }, + { "mul.da.hh", ICLASS_xt_iclass_mac16_da, + 0, + Opcode_mul_da_hh_encode_fns, 0, 0 }, + { "mul.dd.ll", ICLASS_xt_iclass_mac16_dd, + 0, + Opcode_mul_dd_ll_encode_fns, 0, 0 }, + { "mul.dd.hl", ICLASS_xt_iclass_mac16_dd, + 0, + Opcode_mul_dd_hl_encode_fns, 0, 0 }, + { "mul.dd.lh", ICLASS_xt_iclass_mac16_dd, + 0, + Opcode_mul_dd_lh_encode_fns, 0, 0 }, + { "mul.dd.hh", ICLASS_xt_iclass_mac16_dd, + 0, + Opcode_mul_dd_hh_encode_fns, 0, 0 }, + { "mula.aa.ll", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_mula_aa_ll_encode_fns, 0, 0 }, + { "mula.aa.hl", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_mula_aa_hl_encode_fns, 0, 0 }, + { "mula.aa.lh", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_mula_aa_lh_encode_fns, 0, 0 }, + { "mula.aa.hh", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_mula_aa_hh_encode_fns, 0, 0 }, + { "muls.aa.ll", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_muls_aa_ll_encode_fns, 0, 0 }, + { "muls.aa.hl", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_muls_aa_hl_encode_fns, 0, 0 }, + { "muls.aa.lh", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_muls_aa_lh_encode_fns, 0, 0 }, + { "muls.aa.hh", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_muls_aa_hh_encode_fns, 0, 0 }, + { "mula.ad.ll", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_mula_ad_ll_encode_fns, 0, 0 }, + { "mula.ad.hl", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_mula_ad_hl_encode_fns, 0, 0 }, + { "mula.ad.lh", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_mula_ad_lh_encode_fns, 0, 0 }, + { "mula.ad.hh", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_mula_ad_hh_encode_fns, 0, 0 }, + { "muls.ad.ll", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_muls_ad_ll_encode_fns, 0, 0 }, + { "muls.ad.hl", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_muls_ad_hl_encode_fns, 0, 0 }, + { "muls.ad.lh", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_muls_ad_lh_encode_fns, 0, 0 }, + { "muls.ad.hh", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_muls_ad_hh_encode_fns, 0, 0 }, + { "mula.da.ll", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_mula_da_ll_encode_fns, 0, 0 }, + { "mula.da.hl", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_mula_da_hl_encode_fns, 0, 0 }, + { "mula.da.lh", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_mula_da_lh_encode_fns, 0, 0 }, + { "mula.da.hh", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_mula_da_hh_encode_fns, 0, 0 }, + { "muls.da.ll", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_muls_da_ll_encode_fns, 0, 0 }, + { "muls.da.hl", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_muls_da_hl_encode_fns, 0, 0 }, + { "muls.da.lh", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_muls_da_lh_encode_fns, 0, 0 }, + { "muls.da.hh", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_muls_da_hh_encode_fns, 0, 0 }, + { "mula.dd.ll", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_mula_dd_ll_encode_fns, 0, 0 }, + { "mula.dd.hl", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_mula_dd_hl_encode_fns, 0, 0 }, + { "mula.dd.lh", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_mula_dd_lh_encode_fns, 0, 0 }, + { "mula.dd.hh", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_mula_dd_hh_encode_fns, 0, 0 }, + { "muls.dd.ll", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_muls_dd_ll_encode_fns, 0, 0 }, + { "muls.dd.hl", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_muls_dd_hl_encode_fns, 0, 0 }, + { "muls.dd.lh", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_muls_dd_lh_encode_fns, 0, 0 }, + { "muls.dd.hh", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_muls_dd_hh_encode_fns, 0, 0 }, + { "mula.da.ll.lddec", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_ll_lddec_encode_fns, 0, 0 }, + { "mula.da.ll.ldinc", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_ll_ldinc_encode_fns, 0, 0 }, + { "mula.da.hl.lddec", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_hl_lddec_encode_fns, 0, 0 }, + { "mula.da.hl.ldinc", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_hl_ldinc_encode_fns, 0, 0 }, + { "mula.da.lh.lddec", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_lh_lddec_encode_fns, 0, 0 }, + { "mula.da.lh.ldinc", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_lh_ldinc_encode_fns, 0, 0 }, + { "mula.da.hh.lddec", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_hh_lddec_encode_fns, 0, 0 }, + { "mula.da.hh.ldinc", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_hh_ldinc_encode_fns, 0, 0 }, + { "mula.dd.ll.lddec", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_ll_lddec_encode_fns, 0, 0 }, + { "mula.dd.ll.ldinc", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_ll_ldinc_encode_fns, 0, 0 }, + { "mula.dd.hl.lddec", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_hl_lddec_encode_fns, 0, 0 }, + { "mula.dd.hl.ldinc", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_hl_ldinc_encode_fns, 0, 0 }, + { "mula.dd.lh.lddec", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_lh_lddec_encode_fns, 0, 0 }, + { "mula.dd.lh.ldinc", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_lh_ldinc_encode_fns, 0, 0 }, + { "mula.dd.hh.lddec", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_hh_lddec_encode_fns, 0, 0 }, + { "mula.dd.hh.ldinc", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_hh_ldinc_encode_fns, 0, 0 }, + { "lddec", ICLASS_xt_iclass_mac16_l, + 0, + Opcode_lddec_encode_fns, 0, 0 }, + { "ldinc", ICLASS_xt_iclass_mac16_l, + 0, + Opcode_ldinc_encode_fns, 0, 0 }, + { "rsr.m0", ICLASS_xt_iclass_rsr_m0, + 0, + Opcode_rsr_m0_encode_fns, 0, 0 }, + { "wsr.m0", ICLASS_xt_iclass_wsr_m0, + 0, + Opcode_wsr_m0_encode_fns, 0, 0 }, + { "xsr.m0", ICLASS_xt_iclass_xsr_m0, + 0, + Opcode_xsr_m0_encode_fns, 0, 0 }, + { "rsr.m1", ICLASS_xt_iclass_rsr_m1, + 0, + Opcode_rsr_m1_encode_fns, 0, 0 }, + { "wsr.m1", ICLASS_xt_iclass_wsr_m1, + 0, + Opcode_wsr_m1_encode_fns, 0, 0 }, + { "xsr.m1", ICLASS_xt_iclass_xsr_m1, + 0, + Opcode_xsr_m1_encode_fns, 0, 0 }, + { "rsr.m2", ICLASS_xt_iclass_rsr_m2, + 0, + Opcode_rsr_m2_encode_fns, 0, 0 }, + { "wsr.m2", ICLASS_xt_iclass_wsr_m2, + 0, + Opcode_wsr_m2_encode_fns, 0, 0 }, + { "xsr.m2", ICLASS_xt_iclass_xsr_m2, + 0, + Opcode_xsr_m2_encode_fns, 0, 0 }, + { "rsr.m3", ICLASS_xt_iclass_rsr_m3, + 0, + Opcode_rsr_m3_encode_fns, 0, 0 }, + { "wsr.m3", ICLASS_xt_iclass_wsr_m3, + 0, + Opcode_wsr_m3_encode_fns, 0, 0 }, + { "xsr.m3", ICLASS_xt_iclass_xsr_m3, + 0, + Opcode_xsr_m3_encode_fns, 0, 0 }, + { "rsr.acclo", ICLASS_xt_iclass_rsr_acclo, + 0, + Opcode_rsr_acclo_encode_fns, 0, 0 }, + { "wsr.acclo", ICLASS_xt_iclass_wsr_acclo, + 0, + Opcode_wsr_acclo_encode_fns, 0, 0 }, + { "xsr.acclo", ICLASS_xt_iclass_xsr_acclo, + 0, + Opcode_xsr_acclo_encode_fns, 0, 0 }, + { "rsr.acchi", ICLASS_xt_iclass_rsr_acchi, + 0, + Opcode_rsr_acchi_encode_fns, 0, 0 }, + { "wsr.acchi", ICLASS_xt_iclass_wsr_acchi, + 0, + Opcode_wsr_acchi_encode_fns, 0, 0 }, + { "xsr.acchi", ICLASS_xt_iclass_xsr_acchi, + 0, + Opcode_xsr_acchi_encode_fns, 0, 0 }, + { "rfi", ICLASS_xt_iclass_rfi, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfi_encode_fns, 0, 0 }, + { "waiti", ICLASS_xt_iclass_wait, + 0, + Opcode_waiti_encode_fns, 0, 0 }, + { "rsr.interrupt", ICLASS_xt_iclass_rsr_interrupt, + 0, + Opcode_rsr_interrupt_encode_fns, 0, 0 }, + { "wsr.intset", ICLASS_xt_iclass_wsr_intset, + 0, + Opcode_wsr_intset_encode_fns, 0, 0 }, + { "wsr.intclear", ICLASS_xt_iclass_wsr_intclear, + 0, + Opcode_wsr_intclear_encode_fns, 0, 0 }, + { "rsr.intenable", ICLASS_xt_iclass_rsr_intenable, + 0, + Opcode_rsr_intenable_encode_fns, 0, 0 }, + { "wsr.intenable", ICLASS_xt_iclass_wsr_intenable, + 0, + Opcode_wsr_intenable_encode_fns, 0, 0 }, + { "xsr.intenable", ICLASS_xt_iclass_xsr_intenable, + 0, + Opcode_xsr_intenable_encode_fns, 0, 0 }, + { "break", ICLASS_xt_iclass_break, + 0, + Opcode_break_encode_fns, 0, 0 }, + { "break.n", ICLASS_xt_iclass_break_n, + 0, + Opcode_break_n_encode_fns, 0, 0 }, + { "rsr.dbreaka0", ICLASS_xt_iclass_rsr_dbreaka0, + 0, + Opcode_rsr_dbreaka0_encode_fns, 0, 0 }, + { "wsr.dbreaka0", ICLASS_xt_iclass_wsr_dbreaka0, + 0, + Opcode_wsr_dbreaka0_encode_fns, 0, 0 }, + { "xsr.dbreaka0", ICLASS_xt_iclass_xsr_dbreaka0, + 0, + Opcode_xsr_dbreaka0_encode_fns, 0, 0 }, + { "rsr.dbreakc0", ICLASS_xt_iclass_rsr_dbreakc0, + 0, + Opcode_rsr_dbreakc0_encode_fns, 0, 0 }, + { "wsr.dbreakc0", ICLASS_xt_iclass_wsr_dbreakc0, + 0, + Opcode_wsr_dbreakc0_encode_fns, 0, 0 }, + { "xsr.dbreakc0", ICLASS_xt_iclass_xsr_dbreakc0, + 0, + Opcode_xsr_dbreakc0_encode_fns, 0, 0 }, + { "rsr.dbreaka1", ICLASS_xt_iclass_rsr_dbreaka1, + 0, + Opcode_rsr_dbreaka1_encode_fns, 0, 0 }, + { "wsr.dbreaka1", ICLASS_xt_iclass_wsr_dbreaka1, + 0, + Opcode_wsr_dbreaka1_encode_fns, 0, 0 }, + { "xsr.dbreaka1", ICLASS_xt_iclass_xsr_dbreaka1, + 0, + Opcode_xsr_dbreaka1_encode_fns, 0, 0 }, + { "rsr.dbreakc1", ICLASS_xt_iclass_rsr_dbreakc1, + 0, + Opcode_rsr_dbreakc1_encode_fns, 0, 0 }, + { "wsr.dbreakc1", ICLASS_xt_iclass_wsr_dbreakc1, + 0, + Opcode_wsr_dbreakc1_encode_fns, 0, 0 }, + { "xsr.dbreakc1", ICLASS_xt_iclass_xsr_dbreakc1, + 0, + Opcode_xsr_dbreakc1_encode_fns, 0, 0 }, + { "rsr.ibreaka0", ICLASS_xt_iclass_rsr_ibreaka0, + 0, + Opcode_rsr_ibreaka0_encode_fns, 0, 0 }, + { "wsr.ibreaka0", ICLASS_xt_iclass_wsr_ibreaka0, + 0, + Opcode_wsr_ibreaka0_encode_fns, 0, 0 }, + { "xsr.ibreaka0", ICLASS_xt_iclass_xsr_ibreaka0, + 0, + Opcode_xsr_ibreaka0_encode_fns, 0, 0 }, + { "rsr.ibreaka1", ICLASS_xt_iclass_rsr_ibreaka1, + 0, + Opcode_rsr_ibreaka1_encode_fns, 0, 0 }, + { "wsr.ibreaka1", ICLASS_xt_iclass_wsr_ibreaka1, + 0, + Opcode_wsr_ibreaka1_encode_fns, 0, 0 }, + { "xsr.ibreaka1", ICLASS_xt_iclass_xsr_ibreaka1, + 0, + Opcode_xsr_ibreaka1_encode_fns, 0, 0 }, + { "rsr.ibreakenable", ICLASS_xt_iclass_rsr_ibreakenable, + 0, + Opcode_rsr_ibreakenable_encode_fns, 0, 0 }, + { "wsr.ibreakenable", ICLASS_xt_iclass_wsr_ibreakenable, + 0, + Opcode_wsr_ibreakenable_encode_fns, 0, 0 }, + { "xsr.ibreakenable", ICLASS_xt_iclass_xsr_ibreakenable, + 0, + Opcode_xsr_ibreakenable_encode_fns, 0, 0 }, + { "rsr.debugcause", ICLASS_xt_iclass_rsr_debugcause, + 0, + Opcode_rsr_debugcause_encode_fns, 0, 0 }, + { "wsr.debugcause", ICLASS_xt_iclass_wsr_debugcause, + 0, + Opcode_wsr_debugcause_encode_fns, 0, 0 }, + { "xsr.debugcause", ICLASS_xt_iclass_xsr_debugcause, + 0, + Opcode_xsr_debugcause_encode_fns, 0, 0 }, + { "rsr.icount", ICLASS_xt_iclass_rsr_icount, + 0, + Opcode_rsr_icount_encode_fns, 0, 0 }, + { "wsr.icount", ICLASS_xt_iclass_wsr_icount, + 0, + Opcode_wsr_icount_encode_fns, 0, 0 }, + { "xsr.icount", ICLASS_xt_iclass_xsr_icount, + 0, + Opcode_xsr_icount_encode_fns, 0, 0 }, + { "rsr.icountlevel", ICLASS_xt_iclass_rsr_icountlevel, + 0, + Opcode_rsr_icountlevel_encode_fns, 0, 0 }, + { "wsr.icountlevel", ICLASS_xt_iclass_wsr_icountlevel, + 0, + Opcode_wsr_icountlevel_encode_fns, 0, 0 }, + { "xsr.icountlevel", ICLASS_xt_iclass_xsr_icountlevel, + 0, + Opcode_xsr_icountlevel_encode_fns, 0, 0 }, + { "rsr.ddr", ICLASS_xt_iclass_rsr_ddr, + 0, + Opcode_rsr_ddr_encode_fns, 0, 0 }, + { "wsr.ddr", ICLASS_xt_iclass_wsr_ddr, + 0, + Opcode_wsr_ddr_encode_fns, 0, 0 }, + { "xsr.ddr", ICLASS_xt_iclass_xsr_ddr, + 0, + Opcode_xsr_ddr_encode_fns, 0, 0 }, + { "lddr32.p", ICLASS_xt_iclass_lddr32_p, + 0, + Opcode_lddr32_p_encode_fns, 0, 0 }, + { "sddr32.p", ICLASS_xt_iclass_sddr32_p, + 0, + Opcode_sddr32_p_encode_fns, 0, 0 }, + { "rfdo", ICLASS_xt_iclass_rfdo, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfdo_encode_fns, 0, 0 }, + { "rfdd", ICLASS_xt_iclass_rfdd, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfdd_encode_fns, 0, 0 }, + { "wsr.mmid", ICLASS_xt_iclass_wsr_mmid, + 0, + Opcode_wsr_mmid_encode_fns, 0, 0 }, + { "andb", ICLASS_xt_iclass_bbool1, + 0, + Opcode_andb_encode_fns, 0, 0 }, + { "andbc", ICLASS_xt_iclass_bbool1, + 0, + Opcode_andbc_encode_fns, 0, 0 }, + { "orb", ICLASS_xt_iclass_bbool1, + 0, + Opcode_orb_encode_fns, 0, 0 }, + { "orbc", ICLASS_xt_iclass_bbool1, + 0, + Opcode_orbc_encode_fns, 0, 0 }, + { "xorb", ICLASS_xt_iclass_bbool1, + 0, + Opcode_xorb_encode_fns, 0, 0 }, + { "any4", ICLASS_xt_iclass_bbool4, + 0, + Opcode_any4_encode_fns, 0, 0 }, + { "all4", ICLASS_xt_iclass_bbool4, + 0, + Opcode_all4_encode_fns, 0, 0 }, + { "any8", ICLASS_xt_iclass_bbool8, + 0, + Opcode_any8_encode_fns, 0, 0 }, + { "all8", ICLASS_xt_iclass_bbool8, + 0, + Opcode_all8_encode_fns, 0, 0 }, + { "bf", ICLASS_xt_iclass_bbranch, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bf_encode_fns, 0, 0 }, + { "bt", ICLASS_xt_iclass_bbranch, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bt_encode_fns, 0, 0 }, + { "movf", ICLASS_xt_iclass_bmove, + 0, + Opcode_movf_encode_fns, 0, 0 }, + { "movt", ICLASS_xt_iclass_bmove, + 0, + Opcode_movt_encode_fns, 0, 0 }, + { "rsr.br", ICLASS_xt_iclass_RSR_BR, + 0, + Opcode_rsr_br_encode_fns, 0, 0 }, + { "wsr.br", ICLASS_xt_iclass_WSR_BR, + 0, + Opcode_wsr_br_encode_fns, 0, 0 }, + { "xsr.br", ICLASS_xt_iclass_XSR_BR, + 0, + Opcode_xsr_br_encode_fns, 0, 0 }, + { "rsr.ccount", ICLASS_xt_iclass_rsr_ccount, + 0, + Opcode_rsr_ccount_encode_fns, 0, 0 }, + { "wsr.ccount", ICLASS_xt_iclass_wsr_ccount, + 0, + Opcode_wsr_ccount_encode_fns, 0, 0 }, + { "xsr.ccount", ICLASS_xt_iclass_xsr_ccount, + 0, + Opcode_xsr_ccount_encode_fns, 0, 0 }, + { "rsr.ccompare0", ICLASS_xt_iclass_rsr_ccompare0, + 0, + Opcode_rsr_ccompare0_encode_fns, 0, 0 }, + { "wsr.ccompare0", ICLASS_xt_iclass_wsr_ccompare0, + 0, + Opcode_wsr_ccompare0_encode_fns, 0, 0 }, + { "xsr.ccompare0", ICLASS_xt_iclass_xsr_ccompare0, + 0, + Opcode_xsr_ccompare0_encode_fns, 0, 0 }, + { "rsr.ccompare1", ICLASS_xt_iclass_rsr_ccompare1, + 0, + Opcode_rsr_ccompare1_encode_fns, 0, 0 }, + { "wsr.ccompare1", ICLASS_xt_iclass_wsr_ccompare1, + 0, + Opcode_wsr_ccompare1_encode_fns, 0, 0 }, + { "xsr.ccompare1", ICLASS_xt_iclass_xsr_ccompare1, + 0, + Opcode_xsr_ccompare1_encode_fns, 0, 0 }, + { "rsr.ccompare2", ICLASS_xt_iclass_rsr_ccompare2, + 0, + Opcode_rsr_ccompare2_encode_fns, 0, 0 }, + { "wsr.ccompare2", ICLASS_xt_iclass_wsr_ccompare2, + 0, + Opcode_wsr_ccompare2_encode_fns, 0, 0 }, + { "xsr.ccompare2", ICLASS_xt_iclass_xsr_ccompare2, + 0, + Opcode_xsr_ccompare2_encode_fns, 0, 0 }, + { "idtlb", ICLASS_xt_iclass_idtlb, + 0, + Opcode_idtlb_encode_fns, 0, 0 }, + { "pdtlb", ICLASS_xt_iclass_rdtlb, + 0, + Opcode_pdtlb_encode_fns, 0, 0 }, + { "rdtlb0", ICLASS_xt_iclass_rdtlb, + 0, + Opcode_rdtlb0_encode_fns, 0, 0 }, + { "rdtlb1", ICLASS_xt_iclass_rdtlb, + 0, + Opcode_rdtlb1_encode_fns, 0, 0 }, + { "wdtlb", ICLASS_xt_iclass_wdtlb, + 0, + Opcode_wdtlb_encode_fns, 0, 0 }, + { "iitlb", ICLASS_xt_iclass_iitlb, + 0, + Opcode_iitlb_encode_fns, 0, 0 }, + { "pitlb", ICLASS_xt_iclass_ritlb, + 0, + Opcode_pitlb_encode_fns, 0, 0 }, + { "ritlb0", ICLASS_xt_iclass_ritlb, + 0, + Opcode_ritlb0_encode_fns, 0, 0 }, + { "ritlb1", ICLASS_xt_iclass_ritlb, + 0, + Opcode_ritlb1_encode_fns, 0, 0 }, + { "witlb", ICLASS_xt_iclass_witlb, + 0, + Opcode_witlb_encode_fns, 0, 0 }, + { "rsr.cpenable", ICLASS_xt_iclass_rsr_cpenable, + 0, + Opcode_rsr_cpenable_encode_fns, 0, 0 }, + { "wsr.cpenable", ICLASS_xt_iclass_wsr_cpenable, + 0, + Opcode_wsr_cpenable_encode_fns, 0, 0 }, + { "xsr.cpenable", ICLASS_xt_iclass_xsr_cpenable, + 0, + Opcode_xsr_cpenable_encode_fns, 0, 0 }, + { "clamps", ICLASS_xt_iclass_clamp, + 0, + Opcode_clamps_encode_fns, 0, 0 }, + { "min", ICLASS_xt_iclass_minmax, + 0, + Opcode_min_encode_fns, 0, 0 }, + { "max", ICLASS_xt_iclass_minmax, + 0, + Opcode_max_encode_fns, 0, 0 }, + { "minu", ICLASS_xt_iclass_minmax, + 0, + Opcode_minu_encode_fns, 0, 0 }, + { "maxu", ICLASS_xt_iclass_minmax, + 0, + Opcode_maxu_encode_fns, 0, 0 }, + { "nsa", ICLASS_xt_iclass_nsa, + 0, + Opcode_nsa_encode_fns, 0, 0 }, + { "nsau", ICLASS_xt_iclass_nsa, + 0, + Opcode_nsau_encode_fns, 0, 0 }, + { "sext", ICLASS_xt_iclass_sx, + 0, + Opcode_sext_encode_fns, 0, 0 }, + { "l32ai", ICLASS_xt_iclass_l32ai, + 0, + Opcode_l32ai_encode_fns, 0, 0 }, + { "s32ri", ICLASS_xt_iclass_s32ri, + 0, + Opcode_s32ri_encode_fns, 0, 0 }, + { "s32c1i", ICLASS_xt_iclass_s32c1i, + 0, + Opcode_s32c1i_encode_fns, 0, 0 }, + { "rsr.scompare1", ICLASS_xt_iclass_rsr_scompare1, + 0, + Opcode_rsr_scompare1_encode_fns, 0, 0 }, + { "wsr.scompare1", ICLASS_xt_iclass_wsr_scompare1, + 0, + Opcode_wsr_scompare1_encode_fns, 0, 0 }, + { "xsr.scompare1", ICLASS_xt_iclass_xsr_scompare1, + 0, + Opcode_xsr_scompare1_encode_fns, 0, 0 }, + { "rsr.atomctl", ICLASS_xt_iclass_rsr_atomctl, + 0, + Opcode_rsr_atomctl_encode_fns, 0, 0 }, + { "wsr.atomctl", ICLASS_xt_iclass_wsr_atomctl, + 0, + Opcode_wsr_atomctl_encode_fns, 0, 0 }, + { "xsr.atomctl", ICLASS_xt_iclass_xsr_atomctl, + 0, + Opcode_xsr_atomctl_encode_fns, 0, 0 }, + { "quou", ICLASS_xt_iclass_div, + 0, + Opcode_quou_encode_fns, 0, 0 }, + { "quos", ICLASS_xt_iclass_div, + 0, + Opcode_quos_encode_fns, 0, 0 }, + { "remu", ICLASS_xt_iclass_div, + 0, + Opcode_remu_encode_fns, 0, 0 }, + { "rems", ICLASS_xt_iclass_div, + 0, + Opcode_rems_encode_fns, 0, 0 }, + { "rer", ICLASS_xt_iclass_rer, + 0, + Opcode_rer_encode_fns, 0, 0 }, + { "wer", ICLASS_xt_iclass_wer, + 0, + Opcode_wer_encode_fns, 0, 0 }, + { "f64iter", ICLASS_iclass_F64ITER, + 0, + Opcode_f64iter_encode_fns, 0, 0 }, + { "f64rnd", ICLASS_iclass_F64RND, + 0, + Opcode_f64rnd_encode_fns, 0, 0 }, + { "f64addc", ICLASS_iclass_F64ADDC_F64SUBC, + 0, + Opcode_f64addc_encode_fns, 0, 0 }, + { "f64subc", ICLASS_iclass_F64ADDC_F64SUBC, + 0, + Opcode_f64subc_encode_fns, 0, 0 }, + { "f64sig", ICLASS_iclass_F64SIG, + 0, + Opcode_f64sig_encode_fns, 0, 0 }, + { "f64cmpl", ICLASS_iclass_F64CMPL, + 0, + Opcode_f64cmpl_encode_fns, 0, 0 }, + { "f64cmph", ICLASS_iclass_F64CMPH, + 0, + Opcode_f64cmph_encode_fns, 0, 0 }, + { "f64norm", ICLASS_iclass_F64NORM, + 0, + Opcode_f64norm_encode_fns, 0, 0 }, + { "f64sexp", ICLASS_iclass_F64SEXP, + 0, + Opcode_f64sexp_encode_fns, 0, 0 }, + { "rf64r", ICLASS_iclass_RF64R, + 0, + Opcode_rf64r_encode_fns, 0, 0 }, + { "wf64r", ICLASS_iclass_WF64R, + 0, + Opcode_wf64r_encode_fns, 0, 0 }, + { "rur.f64r_lo", ICLASS_rur_f64r_lo, + 0, + Opcode_rur_f64r_lo_encode_fns, 0, 0 }, + { "wur.f64r_lo", ICLASS_wur_f64r_lo, + 0, + Opcode_wur_f64r_lo_encode_fns, 0, 0 }, + { "rur.f64r_hi", ICLASS_rur_f64r_hi, + 0, + Opcode_rur_f64r_hi_encode_fns, 0, 0 }, + { "wur.f64r_hi", ICLASS_wur_f64r_hi, + 0, + Opcode_wur_f64r_hi_encode_fns, 0, 0 }, + { "rur.f64s", ICLASS_rur_f64s, + 0, + Opcode_rur_f64s_encode_fns, 0, 0 }, + { "wur.f64s", ICLASS_wur_f64s, + 0, + Opcode_wur_f64s_encode_fns, 0, 0 }, + { "rur.fcr", ICLASS_rur_fcr, + 0, + Opcode_rur_fcr_encode_fns, 0, 0 }, + { "wur.fcr", ICLASS_wur_fcr, + 0, + Opcode_wur_fcr_encode_fns, 0, 0 }, + { "rur.fsr", ICLASS_rur_fsr, + 0, + Opcode_rur_fsr_encode_fns, 0, 0 }, + { "wur.fsr", ICLASS_wur_fsr, + 0, + Opcode_wur_fsr_encode_fns, 0, 0 }, + { "rur.expstate", ICLASS_rur_expstate, + 0, + Opcode_rur_expstate_encode_fns, 0, 0 }, + { "wur.expstate", ICLASS_wur_expstate, + 0, + Opcode_wur_expstate_encode_fns, 0, 0 }, + { "read_impwire", ICLASS_iclass_READ_IMPWIRE, + 0, + Opcode_read_impwire_encode_fns, 0, 0 }, + { "setb_expstate", ICLASS_iclass_SETB_EXPSTATE, + 0, + Opcode_setb_expstate_encode_fns, 0, 0 }, + { "clrb_expstate", ICLASS_iclass_CLRB_EXPSTATE, + 0, + Opcode_clrb_expstate_encode_fns, 0, 0 }, + { "wrmsk_expstate", ICLASS_iclass_WRMSK_EXPSTATE, + 0, + Opcode_wrmsk_expstate_encode_fns, 0, 0 } +}; + +enum xtensa_opcode_id { + OPCODE_LSI, + OPCODE_LSIP, + OPCODE_LSX, + OPCODE_LSXP, + OPCODE_SSI, + OPCODE_SSIP, + OPCODE_SSX, + OPCODE_SSXP, + OPCODE_ABS_S, + OPCODE_NEG_S, + OPCODE_MOV_S, + OPCODE_MOVEQZ_S, + OPCODE_MOVNEZ_S, + OPCODE_MOVLTZ_S, + OPCODE_MOVGEZ_S, + OPCODE_MOVF_S, + OPCODE_MOVT_S, + OPCODE_WFR, + OPCODE_RFR, + OPCODE_ROUND_S, + OPCODE_CEIL_S, + OPCODE_FLOOR_S, + OPCODE_TRUNC_S, + OPCODE_UTRUNC_S, + OPCODE_FLOAT_S, + OPCODE_UFLOAT_S, + OPCODE_UN_S, + OPCODE_ULT_S, + OPCODE_ULE_S, + OPCODE_UEQ_S, + OPCODE_OLT_S, + OPCODE_OLE_S, + OPCODE_OEQ_S, + OPCODE_ADD_S, + OPCODE_SUB_S, + OPCODE_MUL_S, + OPCODE_MADD_S, + OPCODE_MSUB_S, + OPCODE_SQRT0_S, + OPCODE_DIV0_S, + OPCODE_RECIP0_S, + OPCODE_RSQRT0_S, + OPCODE_MADDN_S, + OPCODE_DIVN_S, + OPCODE_CONST_S, + OPCODE_NEXP01_S, + OPCODE_ADDEXP_S, + OPCODE_ADDEXPM_S, + OPCODE_MKDADJ_S, + OPCODE_MKSADJ_S, + OPCODE_EXCW, + OPCODE_RFE, + OPCODE_RFDE, + OPCODE_SYSCALL, + OPCODE_CALL12, + OPCODE_CALL8, + OPCODE_CALL4, + OPCODE_CALLX12, + OPCODE_CALLX8, + OPCODE_CALLX4, + OPCODE_ENTRY, + OPCODE_MOVSP, + OPCODE_ROTW, + OPCODE_RETW, + OPCODE_RETW_N, + OPCODE_RFWO, + OPCODE_RFWU, + OPCODE_L32E, + OPCODE_S32E, + OPCODE_RSR_WINDOWBASE, + OPCODE_WSR_WINDOWBASE, + OPCODE_XSR_WINDOWBASE, + OPCODE_RSR_WINDOWSTART, + OPCODE_WSR_WINDOWSTART, + OPCODE_XSR_WINDOWSTART, + OPCODE_ADD_N, + OPCODE_ADDI_N, + OPCODE_BEQZ_N, + OPCODE_BNEZ_N, + OPCODE_ILL_N, + OPCODE_L32I_N, + OPCODE_MOV_N, + OPCODE_MOVI_N, + OPCODE_NOP_N, + OPCODE_RET_N, + OPCODE_S32I_N, + OPCODE_RUR_THREADPTR, + OPCODE_WUR_THREADPTR, + OPCODE_ADDI, + OPCODE_ADDMI, + OPCODE_ADD, + OPCODE_SUB, + OPCODE_ADDX2, + OPCODE_ADDX4, + OPCODE_ADDX8, + OPCODE_SUBX2, + OPCODE_SUBX4, + OPCODE_SUBX8, + OPCODE_AND, + OPCODE_OR, + OPCODE_XOR, + OPCODE_BEQI, + OPCODE_BNEI, + OPCODE_BGEI, + OPCODE_BLTI, + OPCODE_BBCI, + OPCODE_BBSI, + OPCODE_BGEUI, + OPCODE_BLTUI, + OPCODE_BEQ, + OPCODE_BNE, + OPCODE_BGE, + OPCODE_BLT, + OPCODE_BGEU, + OPCODE_BLTU, + OPCODE_BANY, + OPCODE_BNONE, + OPCODE_BALL, + OPCODE_BNALL, + OPCODE_BBC, + OPCODE_BBS, + OPCODE_BEQZ, + OPCODE_BNEZ, + OPCODE_BGEZ, + OPCODE_BLTZ, + OPCODE_CALL0, + OPCODE_CALLX0, + OPCODE_EXTUI, + OPCODE_ILL, + OPCODE_J, + OPCODE_JX, + OPCODE_L16UI, + OPCODE_L16SI, + OPCODE_L32I, + OPCODE_L32R, + OPCODE_L8UI, + OPCODE_LOOP, + OPCODE_LOOPNEZ, + OPCODE_LOOPGTZ, + OPCODE_MOVI, + OPCODE_MOVEQZ, + OPCODE_MOVNEZ, + OPCODE_MOVLTZ, + OPCODE_MOVGEZ, + OPCODE_NEG, + OPCODE_ABS, + OPCODE_NOP, + OPCODE_RET, + OPCODE_SIMCALL, + OPCODE_S16I, + OPCODE_S32I, + OPCODE_S32NB, + OPCODE_S8I, + OPCODE_SSR, + OPCODE_SSL, + OPCODE_SSA8L, + OPCODE_SSA8B, + OPCODE_SSAI, + OPCODE_SLL, + OPCODE_SRC, + OPCODE_SRL, + OPCODE_SRA, + OPCODE_SLLI, + OPCODE_SRAI, + OPCODE_SRLI, + OPCODE_MEMW, + OPCODE_EXTW, + OPCODE_ISYNC, + OPCODE_RSYNC, + OPCODE_ESYNC, + OPCODE_DSYNC, + OPCODE_RSIL, + OPCODE_RSR_LEND, + OPCODE_WSR_LEND, + OPCODE_XSR_LEND, + OPCODE_RSR_LCOUNT, + OPCODE_WSR_LCOUNT, + OPCODE_XSR_LCOUNT, + OPCODE_RSR_LBEG, + OPCODE_WSR_LBEG, + OPCODE_XSR_LBEG, + OPCODE_RSR_SAR, + OPCODE_WSR_SAR, + OPCODE_XSR_SAR, + OPCODE_RSR_MEMCTL, + OPCODE_WSR_MEMCTL, + OPCODE_XSR_MEMCTL, + OPCODE_RSR_LITBASE, + OPCODE_WSR_LITBASE, + OPCODE_XSR_LITBASE, + OPCODE_RSR_CONFIGID0, + OPCODE_WSR_CONFIGID0, + OPCODE_RSR_CONFIGID1, + OPCODE_RSR_PS, + OPCODE_WSR_PS, + OPCODE_XSR_PS, + OPCODE_RSR_EPC1, + OPCODE_WSR_EPC1, + OPCODE_XSR_EPC1, + OPCODE_RSR_EXCSAVE1, + OPCODE_WSR_EXCSAVE1, + OPCODE_XSR_EXCSAVE1, + OPCODE_RSR_EPC2, + OPCODE_WSR_EPC2, + OPCODE_XSR_EPC2, + OPCODE_RSR_EXCSAVE2, + OPCODE_WSR_EXCSAVE2, + OPCODE_XSR_EXCSAVE2, + OPCODE_RSR_EPC3, + OPCODE_WSR_EPC3, + OPCODE_XSR_EPC3, + OPCODE_RSR_EXCSAVE3, + OPCODE_WSR_EXCSAVE3, + OPCODE_XSR_EXCSAVE3, + OPCODE_RSR_EPC4, + OPCODE_WSR_EPC4, + OPCODE_XSR_EPC4, + OPCODE_RSR_EXCSAVE4, + OPCODE_WSR_EXCSAVE4, + OPCODE_XSR_EXCSAVE4, + OPCODE_RSR_EPC5, + OPCODE_WSR_EPC5, + OPCODE_XSR_EPC5, + OPCODE_RSR_EXCSAVE5, + OPCODE_WSR_EXCSAVE5, + OPCODE_XSR_EXCSAVE5, + OPCODE_RSR_EPC6, + OPCODE_WSR_EPC6, + OPCODE_XSR_EPC6, + OPCODE_RSR_EXCSAVE6, + OPCODE_WSR_EXCSAVE6, + OPCODE_XSR_EXCSAVE6, + OPCODE_RSR_EPC7, + OPCODE_WSR_EPC7, + OPCODE_XSR_EPC7, + OPCODE_RSR_EXCSAVE7, + OPCODE_WSR_EXCSAVE7, + OPCODE_XSR_EXCSAVE7, + OPCODE_RSR_EPS2, + OPCODE_WSR_EPS2, + OPCODE_XSR_EPS2, + OPCODE_RSR_EPS3, + OPCODE_WSR_EPS3, + OPCODE_XSR_EPS3, + OPCODE_RSR_EPS4, + OPCODE_WSR_EPS4, + OPCODE_XSR_EPS4, + OPCODE_RSR_EPS5, + OPCODE_WSR_EPS5, + OPCODE_XSR_EPS5, + OPCODE_RSR_EPS6, + OPCODE_WSR_EPS6, + OPCODE_XSR_EPS6, + OPCODE_RSR_EPS7, + OPCODE_WSR_EPS7, + OPCODE_XSR_EPS7, + OPCODE_RSR_EXCVADDR, + OPCODE_WSR_EXCVADDR, + OPCODE_XSR_EXCVADDR, + OPCODE_RSR_DEPC, + OPCODE_WSR_DEPC, + OPCODE_XSR_DEPC, + OPCODE_RSR_EXCCAUSE, + OPCODE_WSR_EXCCAUSE, + OPCODE_XSR_EXCCAUSE, + OPCODE_RSR_MISC0, + OPCODE_WSR_MISC0, + OPCODE_XSR_MISC0, + OPCODE_RSR_MISC1, + OPCODE_WSR_MISC1, + OPCODE_XSR_MISC1, + OPCODE_RSR_MISC2, + OPCODE_WSR_MISC2, + OPCODE_XSR_MISC2, + OPCODE_RSR_MISC3, + OPCODE_WSR_MISC3, + OPCODE_XSR_MISC3, + OPCODE_RSR_PRID, + OPCODE_RSR_VECBASE, + OPCODE_WSR_VECBASE, + OPCODE_XSR_VECBASE, + OPCODE_MUL16U, + OPCODE_MUL16S, + OPCODE_MULL, + OPCODE_MULUH, + OPCODE_MULSH, + OPCODE_MUL_AA_LL, + OPCODE_MUL_AA_HL, + OPCODE_MUL_AA_LH, + OPCODE_MUL_AA_HH, + OPCODE_UMUL_AA_LL, + OPCODE_UMUL_AA_HL, + OPCODE_UMUL_AA_LH, + OPCODE_UMUL_AA_HH, + OPCODE_MUL_AD_LL, + OPCODE_MUL_AD_HL, + OPCODE_MUL_AD_LH, + OPCODE_MUL_AD_HH, + OPCODE_MUL_DA_LL, + OPCODE_MUL_DA_HL, + OPCODE_MUL_DA_LH, + OPCODE_MUL_DA_HH, + OPCODE_MUL_DD_LL, + OPCODE_MUL_DD_HL, + OPCODE_MUL_DD_LH, + OPCODE_MUL_DD_HH, + OPCODE_MULA_AA_LL, + OPCODE_MULA_AA_HL, + OPCODE_MULA_AA_LH, + OPCODE_MULA_AA_HH, + OPCODE_MULS_AA_LL, + OPCODE_MULS_AA_HL, + OPCODE_MULS_AA_LH, + OPCODE_MULS_AA_HH, + OPCODE_MULA_AD_LL, + OPCODE_MULA_AD_HL, + OPCODE_MULA_AD_LH, + OPCODE_MULA_AD_HH, + OPCODE_MULS_AD_LL, + OPCODE_MULS_AD_HL, + OPCODE_MULS_AD_LH, + OPCODE_MULS_AD_HH, + OPCODE_MULA_DA_LL, + OPCODE_MULA_DA_HL, + OPCODE_MULA_DA_LH, + OPCODE_MULA_DA_HH, + OPCODE_MULS_DA_LL, + OPCODE_MULS_DA_HL, + OPCODE_MULS_DA_LH, + OPCODE_MULS_DA_HH, + OPCODE_MULA_DD_LL, + OPCODE_MULA_DD_HL, + OPCODE_MULA_DD_LH, + OPCODE_MULA_DD_HH, + OPCODE_MULS_DD_LL, + OPCODE_MULS_DD_HL, + OPCODE_MULS_DD_LH, + OPCODE_MULS_DD_HH, + OPCODE_MULA_DA_LL_LDDEC, + OPCODE_MULA_DA_LL_LDINC, + OPCODE_MULA_DA_HL_LDDEC, + OPCODE_MULA_DA_HL_LDINC, + OPCODE_MULA_DA_LH_LDDEC, + OPCODE_MULA_DA_LH_LDINC, + OPCODE_MULA_DA_HH_LDDEC, + OPCODE_MULA_DA_HH_LDINC, + OPCODE_MULA_DD_LL_LDDEC, + OPCODE_MULA_DD_LL_LDINC, + OPCODE_MULA_DD_HL_LDDEC, + OPCODE_MULA_DD_HL_LDINC, + OPCODE_MULA_DD_LH_LDDEC, + OPCODE_MULA_DD_LH_LDINC, + OPCODE_MULA_DD_HH_LDDEC, + OPCODE_MULA_DD_HH_LDINC, + OPCODE_LDDEC, + OPCODE_LDINC, + OPCODE_RSR_M0, + OPCODE_WSR_M0, + OPCODE_XSR_M0, + OPCODE_RSR_M1, + OPCODE_WSR_M1, + OPCODE_XSR_M1, + OPCODE_RSR_M2, + OPCODE_WSR_M2, + OPCODE_XSR_M2, + OPCODE_RSR_M3, + OPCODE_WSR_M3, + OPCODE_XSR_M3, + OPCODE_RSR_ACCLO, + OPCODE_WSR_ACCLO, + OPCODE_XSR_ACCLO, + OPCODE_RSR_ACCHI, + OPCODE_WSR_ACCHI, + OPCODE_XSR_ACCHI, + OPCODE_RFI, + OPCODE_WAITI, + OPCODE_RSR_INTERRUPT, + OPCODE_WSR_INTSET, + OPCODE_WSR_INTCLEAR, + OPCODE_RSR_INTENABLE, + OPCODE_WSR_INTENABLE, + OPCODE_XSR_INTENABLE, + OPCODE_BREAK, + OPCODE_BREAK_N, + OPCODE_RSR_DBREAKA0, + OPCODE_WSR_DBREAKA0, + OPCODE_XSR_DBREAKA0, + OPCODE_RSR_DBREAKC0, + OPCODE_WSR_DBREAKC0, + OPCODE_XSR_DBREAKC0, + OPCODE_RSR_DBREAKA1, + OPCODE_WSR_DBREAKA1, + OPCODE_XSR_DBREAKA1, + OPCODE_RSR_DBREAKC1, + OPCODE_WSR_DBREAKC1, + OPCODE_XSR_DBREAKC1, + OPCODE_RSR_IBREAKA0, + OPCODE_WSR_IBREAKA0, + OPCODE_XSR_IBREAKA0, + OPCODE_RSR_IBREAKA1, + OPCODE_WSR_IBREAKA1, + OPCODE_XSR_IBREAKA1, + OPCODE_RSR_IBREAKENABLE, + OPCODE_WSR_IBREAKENABLE, + OPCODE_XSR_IBREAKENABLE, + OPCODE_RSR_DEBUGCAUSE, + OPCODE_WSR_DEBUGCAUSE, + OPCODE_XSR_DEBUGCAUSE, + OPCODE_RSR_ICOUNT, + OPCODE_WSR_ICOUNT, + OPCODE_XSR_ICOUNT, + OPCODE_RSR_ICOUNTLEVEL, + OPCODE_WSR_ICOUNTLEVEL, + OPCODE_XSR_ICOUNTLEVEL, + OPCODE_RSR_DDR, + OPCODE_WSR_DDR, + OPCODE_XSR_DDR, + OPCODE_LDDR32_P, + OPCODE_SDDR32_P, + OPCODE_RFDO, + OPCODE_RFDD, + OPCODE_WSR_MMID, + OPCODE_ANDB, + OPCODE_ANDBC, + OPCODE_ORB, + OPCODE_ORBC, + OPCODE_XORB, + OPCODE_ANY4, + OPCODE_ALL4, + OPCODE_ANY8, + OPCODE_ALL8, + OPCODE_BF, + OPCODE_BT, + OPCODE_MOVF, + OPCODE_MOVT, + OPCODE_RSR_BR, + OPCODE_WSR_BR, + OPCODE_XSR_BR, + OPCODE_RSR_CCOUNT, + OPCODE_WSR_CCOUNT, + OPCODE_XSR_CCOUNT, + OPCODE_RSR_CCOMPARE0, + OPCODE_WSR_CCOMPARE0, + OPCODE_XSR_CCOMPARE0, + OPCODE_RSR_CCOMPARE1, + OPCODE_WSR_CCOMPARE1, + OPCODE_XSR_CCOMPARE1, + OPCODE_RSR_CCOMPARE2, + OPCODE_WSR_CCOMPARE2, + OPCODE_XSR_CCOMPARE2, + OPCODE_IDTLB, + OPCODE_PDTLB, + OPCODE_RDTLB0, + OPCODE_RDTLB1, + OPCODE_WDTLB, + OPCODE_IITLB, + OPCODE_PITLB, + OPCODE_RITLB0, + OPCODE_RITLB1, + OPCODE_WITLB, + OPCODE_RSR_CPENABLE, + OPCODE_WSR_CPENABLE, + OPCODE_XSR_CPENABLE, + OPCODE_CLAMPS, + OPCODE_MIN, + OPCODE_MAX, + OPCODE_MINU, + OPCODE_MAXU, + OPCODE_NSA, + OPCODE_NSAU, + OPCODE_SEXT, + OPCODE_L32AI, + OPCODE_S32RI, + OPCODE_S32C1I, + OPCODE_RSR_SCOMPARE1, + OPCODE_WSR_SCOMPARE1, + OPCODE_XSR_SCOMPARE1, + OPCODE_RSR_ATOMCTL, + OPCODE_WSR_ATOMCTL, + OPCODE_XSR_ATOMCTL, + OPCODE_QUOU, + OPCODE_QUOS, + OPCODE_REMU, + OPCODE_REMS, + OPCODE_RER, + OPCODE_WER, + OPCODE_F64ITER, + OPCODE_F64RND, + OPCODE_F64ADDC, + OPCODE_F64SUBC, + OPCODE_F64SIG, + OPCODE_F64CMPL, + OPCODE_F64CMPH, + OPCODE_F64NORM, + OPCODE_F64SEXP, + OPCODE_RF64R, + OPCODE_WF64R, + OPCODE_RUR_F64R_LO, + OPCODE_WUR_F64R_LO, + OPCODE_RUR_F64R_HI, + OPCODE_WUR_F64R_HI, + OPCODE_RUR_F64S, + OPCODE_WUR_F64S, + OPCODE_RUR_FCR, + OPCODE_WUR_FCR, + OPCODE_RUR_FSR, + OPCODE_WUR_FSR, + OPCODE_RUR_EXPSTATE, + OPCODE_WUR_EXPSTATE, + OPCODE_READ_IMPWIRE, + OPCODE_SETB_EXPSTATE, + OPCODE_CLRB_EXPSTATE, + OPCODE_WRMSK_EXPSTATE +}; + + +/* Slot-specific opcode decode functions. */ + +static int +Slot_inst_decode (const xtensa_insnbuf insn) +{ + if (Field_op0_Slot_inst_get (insn) == 0) + { + if (Field_op1_Slot_inst_get (insn) == 0) + { + if (Field_op2_Slot_inst_get (insn) == 0) + { + if (Field_r_Slot_inst_get (insn) == 0) + { + if (Field_m_Slot_inst_get (insn) == 0 && + Field_s_Slot_inst_get (insn) == 0 && + Field_n_Slot_inst_get (insn) == 0) + return OPCODE_ILL; + if (Field_m_Slot_inst_get (insn) == 2) + { + if (Field_n_Slot_inst_get (insn) == 0) + return OPCODE_RET; + if (Field_n_Slot_inst_get (insn) == 1) + return OPCODE_RETW; + if (Field_n_Slot_inst_get (insn) == 2) + return OPCODE_JX; + } + if (Field_m_Slot_inst_get (insn) == 3) + { + if (Field_n_Slot_inst_get (insn) == 0) + return OPCODE_CALLX0; + if (Field_n_Slot_inst_get (insn) == 1) + return OPCODE_CALLX4; + if (Field_n_Slot_inst_get (insn) == 2) + return OPCODE_CALLX8; + if (Field_n_Slot_inst_get (insn) == 3) + return OPCODE_CALLX12; + } + } + if (Field_r_Slot_inst_get (insn) == 1) + return OPCODE_MOVSP; + if (Field_r_Slot_inst_get (insn) == 2) + { + if (Field_s_Slot_inst_get (insn) == 0) + { + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_ISYNC; + if (Field_t_Slot_inst_get (insn) == 1) + return OPCODE_RSYNC; + if (Field_t_Slot_inst_get (insn) == 2) + return OPCODE_ESYNC; + if (Field_t_Slot_inst_get (insn) == 3) + return OPCODE_DSYNC; + if (Field_t_Slot_inst_get (insn) == 8) + return OPCODE_EXCW; + if (Field_t_Slot_inst_get (insn) == 12) + return OPCODE_MEMW; + if (Field_t_Slot_inst_get (insn) == 13) + return OPCODE_EXTW; + if (Field_t_Slot_inst_get (insn) == 15) + return OPCODE_NOP; + } + } + if (Field_r_Slot_inst_get (insn) == 3) + { + if (Field_t_Slot_inst_get (insn) == 0) + { + if (Field_s_Slot_inst_get (insn) == 0) + return OPCODE_RFE; + if (Field_s_Slot_inst_get (insn) == 2) + return OPCODE_RFDE; + if (Field_s_Slot_inst_get (insn) == 4) + return OPCODE_RFWO; + if (Field_s_Slot_inst_get (insn) == 5) + return OPCODE_RFWU; + } + if (Field_t_Slot_inst_get (insn) == 1) + return OPCODE_RFI; + } + if (Field_r_Slot_inst_get (insn) == 4) + return OPCODE_BREAK; + if (Field_r_Slot_inst_get (insn) == 5) + { + if (Field_s_Slot_inst_get (insn) == 0 && + Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SYSCALL; + if (Field_s_Slot_inst_get (insn) == 1 && + Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SIMCALL; + } + if (Field_r_Slot_inst_get (insn) == 6) + return OPCODE_RSIL; + if (Field_r_Slot_inst_get (insn) == 7 && + Field_t_Slot_inst_get (insn) == 0) + return OPCODE_WAITI; + if (Field_r_Slot_inst_get (insn) == 7) + { + if (Field_t_Slot_inst_get (insn) == 14) + return OPCODE_LDDR32_P; + if (Field_t_Slot_inst_get (insn) == 15) + return OPCODE_SDDR32_P; + } + if (Field_r_Slot_inst_get (insn) == 8) + return OPCODE_ANY4; + if (Field_r_Slot_inst_get (insn) == 9) + return OPCODE_ALL4; + if (Field_r_Slot_inst_get (insn) == 10) + return OPCODE_ANY8; + if (Field_r_Slot_inst_get (insn) == 11) + return OPCODE_ALL8; + } + if (Field_op2_Slot_inst_get (insn) == 1) + return OPCODE_AND; + if (Field_op2_Slot_inst_get (insn) == 2) + return OPCODE_OR; + if (Field_op2_Slot_inst_get (insn) == 3) + return OPCODE_XOR; + if (Field_op2_Slot_inst_get (insn) == 4) + { + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSR; + if (Field_r_Slot_inst_get (insn) == 1 && + Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSL; + if (Field_r_Slot_inst_get (insn) == 2 && + Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSA8L; + if (Field_r_Slot_inst_get (insn) == 3 && + Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSA8B; + if (Field_r_Slot_inst_get (insn) == 4 && + Field_thi3_Slot_inst_get (insn) == 0) + return OPCODE_SSAI; + if (Field_r_Slot_inst_get (insn) == 6) + return OPCODE_RER; + if (Field_r_Slot_inst_get (insn) == 7) + return OPCODE_WER; + if (Field_r_Slot_inst_get (insn) == 8 && + Field_s_Slot_inst_get (insn) == 0) + return OPCODE_ROTW; + if (Field_r_Slot_inst_get (insn) == 14) + return OPCODE_NSA; + if (Field_r_Slot_inst_get (insn) == 15) + return OPCODE_NSAU; + } + if (Field_op2_Slot_inst_get (insn) == 5) + { + if (Field_r_Slot_inst_get (insn) == 3) + return OPCODE_RITLB0; + if (Field_r_Slot_inst_get (insn) == 4 && + Field_t_Slot_inst_get (insn) == 0) + return OPCODE_IITLB; + if (Field_r_Slot_inst_get (insn) == 5) + return OPCODE_PITLB; + if (Field_r_Slot_inst_get (insn) == 6) + return OPCODE_WITLB; + if (Field_r_Slot_inst_get (insn) == 7) + return OPCODE_RITLB1; + if (Field_r_Slot_inst_get (insn) == 11) + return OPCODE_RDTLB0; + if (Field_r_Slot_inst_get (insn) == 12 && + Field_t_Slot_inst_get (insn) == 0) + return OPCODE_IDTLB; + if (Field_r_Slot_inst_get (insn) == 13) + return OPCODE_PDTLB; + if (Field_r_Slot_inst_get (insn) == 14) + return OPCODE_WDTLB; + if (Field_r_Slot_inst_get (insn) == 15) + return OPCODE_RDTLB1; + } + if (Field_op2_Slot_inst_get (insn) == 6) + { + if (Field_s_Slot_inst_get (insn) == 0) + return OPCODE_NEG; + if (Field_s_Slot_inst_get (insn) == 1) + return OPCODE_ABS; + } + if (Field_op2_Slot_inst_get (insn) == 8) + return OPCODE_ADD; + if (Field_op2_Slot_inst_get (insn) == 9) + return OPCODE_ADDX2; + if (Field_op2_Slot_inst_get (insn) == 10) + return OPCODE_ADDX4; + if (Field_op2_Slot_inst_get (insn) == 11) + return OPCODE_ADDX8; + if (Field_op2_Slot_inst_get (insn) == 12) + return OPCODE_SUB; + if (Field_op2_Slot_inst_get (insn) == 13) + return OPCODE_SUBX2; + if (Field_op2_Slot_inst_get (insn) == 14) + return OPCODE_SUBX4; + if (Field_op2_Slot_inst_get (insn) == 15) + return OPCODE_SUBX8; + } + if (Field_op1_Slot_inst_get (insn) == 1) + { + if ((Field_op2_Slot_inst_get (insn) == 0 || + Field_op2_Slot_inst_get (insn) == 1)) + return OPCODE_SLLI; + if ((Field_op2_Slot_inst_get (insn) == 2 || + Field_op2_Slot_inst_get (insn) == 3)) + return OPCODE_SRAI; + if (Field_op2_Slot_inst_get (insn) == 4) + return OPCODE_SRLI; + if (Field_op2_Slot_inst_get (insn) == 6) + { + if (Field_sr_Slot_inst_get (insn) == 0) + return OPCODE_XSR_LBEG; + if (Field_sr_Slot_inst_get (insn) == 1) + return OPCODE_XSR_LEND; + if (Field_sr_Slot_inst_get (insn) == 2) + return OPCODE_XSR_LCOUNT; + if (Field_sr_Slot_inst_get (insn) == 3) + return OPCODE_XSR_SAR; + if (Field_sr_Slot_inst_get (insn) == 4) + return OPCODE_XSR_BR; + if (Field_sr_Slot_inst_get (insn) == 5) + return OPCODE_XSR_LITBASE; + if (Field_sr_Slot_inst_get (insn) == 12) + return OPCODE_XSR_SCOMPARE1; + if (Field_sr_Slot_inst_get (insn) == 16) + return OPCODE_XSR_ACCLO; + if (Field_sr_Slot_inst_get (insn) == 17) + return OPCODE_XSR_ACCHI; + if (Field_sr_Slot_inst_get (insn) == 32) + return OPCODE_XSR_M0; + if (Field_sr_Slot_inst_get (insn) == 33) + return OPCODE_XSR_M1; + if (Field_sr_Slot_inst_get (insn) == 34) + return OPCODE_XSR_M2; + if (Field_sr_Slot_inst_get (insn) == 35) + return OPCODE_XSR_M3; + if (Field_sr_Slot_inst_get (insn) == 72) + return OPCODE_XSR_WINDOWBASE; + if (Field_sr_Slot_inst_get (insn) == 73) + return OPCODE_XSR_WINDOWSTART; + if (Field_sr_Slot_inst_get (insn) == 96) + return OPCODE_XSR_IBREAKENABLE; + if (Field_sr_Slot_inst_get (insn) == 97) + return OPCODE_XSR_MEMCTL; + if (Field_sr_Slot_inst_get (insn) == 99) + return OPCODE_XSR_ATOMCTL; + if (Field_sr_Slot_inst_get (insn) == 104) + return OPCODE_XSR_DDR; + if (Field_sr_Slot_inst_get (insn) == 128) + return OPCODE_XSR_IBREAKA0; + if (Field_sr_Slot_inst_get (insn) == 129) + return OPCODE_XSR_IBREAKA1; + if (Field_sr_Slot_inst_get (insn) == 144) + return OPCODE_XSR_DBREAKA0; + if (Field_sr_Slot_inst_get (insn) == 145) + return OPCODE_XSR_DBREAKA1; + if (Field_sr_Slot_inst_get (insn) == 160) + return OPCODE_XSR_DBREAKC0; + if (Field_sr_Slot_inst_get (insn) == 161) + return OPCODE_XSR_DBREAKC1; + if (Field_sr_Slot_inst_get (insn) == 177) + return OPCODE_XSR_EPC1; + if (Field_sr_Slot_inst_get (insn) == 178) + return OPCODE_XSR_EPC2; + if (Field_sr_Slot_inst_get (insn) == 179) + return OPCODE_XSR_EPC3; + if (Field_sr_Slot_inst_get (insn) == 180) + return OPCODE_XSR_EPC4; + if (Field_sr_Slot_inst_get (insn) == 181) + return OPCODE_XSR_EPC5; + if (Field_sr_Slot_inst_get (insn) == 182) + return OPCODE_XSR_EPC6; + if (Field_sr_Slot_inst_get (insn) == 183) + return OPCODE_XSR_EPC7; + if (Field_sr_Slot_inst_get (insn) == 192) + return OPCODE_XSR_DEPC; + if (Field_sr_Slot_inst_get (insn) == 194) + return OPCODE_XSR_EPS2; + if (Field_sr_Slot_inst_get (insn) == 195) + return OPCODE_XSR_EPS3; + if (Field_sr_Slot_inst_get (insn) == 196) + return OPCODE_XSR_EPS4; + if (Field_sr_Slot_inst_get (insn) == 197) + return OPCODE_XSR_EPS5; + if (Field_sr_Slot_inst_get (insn) == 198) + return OPCODE_XSR_EPS6; + if (Field_sr_Slot_inst_get (insn) == 199) + return OPCODE_XSR_EPS7; + if (Field_sr_Slot_inst_get (insn) == 209) + return OPCODE_XSR_EXCSAVE1; + if (Field_sr_Slot_inst_get (insn) == 210) + return OPCODE_XSR_EXCSAVE2; + if (Field_sr_Slot_inst_get (insn) == 211) + return OPCODE_XSR_EXCSAVE3; + if (Field_sr_Slot_inst_get (insn) == 212) + return OPCODE_XSR_EXCSAVE4; + if (Field_sr_Slot_inst_get (insn) == 213) + return OPCODE_XSR_EXCSAVE5; + if (Field_sr_Slot_inst_get (insn) == 214) + return OPCODE_XSR_EXCSAVE6; + if (Field_sr_Slot_inst_get (insn) == 215) + return OPCODE_XSR_EXCSAVE7; + if (Field_sr_Slot_inst_get (insn) == 224) + return OPCODE_XSR_CPENABLE; + if (Field_sr_Slot_inst_get (insn) == 228) + return OPCODE_XSR_INTENABLE; + if (Field_sr_Slot_inst_get (insn) == 230) + return OPCODE_XSR_PS; + if (Field_sr_Slot_inst_get (insn) == 231) + return OPCODE_XSR_VECBASE; + if (Field_sr_Slot_inst_get (insn) == 232) + return OPCODE_XSR_EXCCAUSE; + if (Field_sr_Slot_inst_get (insn) == 233) + return OPCODE_XSR_DEBUGCAUSE; + if (Field_sr_Slot_inst_get (insn) == 234) + return OPCODE_XSR_CCOUNT; + if (Field_sr_Slot_inst_get (insn) == 236) + return OPCODE_XSR_ICOUNT; + if (Field_sr_Slot_inst_get (insn) == 237) + return OPCODE_XSR_ICOUNTLEVEL; + if (Field_sr_Slot_inst_get (insn) == 238) + return OPCODE_XSR_EXCVADDR; + if (Field_sr_Slot_inst_get (insn) == 240) + return OPCODE_XSR_CCOMPARE0; + if (Field_sr_Slot_inst_get (insn) == 241) + return OPCODE_XSR_CCOMPARE1; + if (Field_sr_Slot_inst_get (insn) == 242) + return OPCODE_XSR_CCOMPARE2; + if (Field_sr_Slot_inst_get (insn) == 244) + return OPCODE_XSR_MISC0; + if (Field_sr_Slot_inst_get (insn) == 245) + return OPCODE_XSR_MISC1; + if (Field_sr_Slot_inst_get (insn) == 246) + return OPCODE_XSR_MISC2; + if (Field_sr_Slot_inst_get (insn) == 247) + return OPCODE_XSR_MISC3; + } + if (Field_op2_Slot_inst_get (insn) == 8) + return OPCODE_SRC; + if (Field_op2_Slot_inst_get (insn) == 9 && + Field_s_Slot_inst_get (insn) == 0) + return OPCODE_SRL; + if (Field_op2_Slot_inst_get (insn) == 10 && + Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SLL; + if (Field_op2_Slot_inst_get (insn) == 11 && + Field_s_Slot_inst_get (insn) == 0) + return OPCODE_SRA; + if (Field_op2_Slot_inst_get (insn) == 12) + return OPCODE_MUL16U; + if (Field_op2_Slot_inst_get (insn) == 13) + return OPCODE_MUL16S; + if (Field_op2_Slot_inst_get (insn) == 15) + { + if (Field_r_Slot_inst_get (insn) == 14 && + Field_t_Slot_inst_get (insn) == 0) + return OPCODE_RFDO; + if (Field_r_Slot_inst_get (insn) == 14 && + Field_t_Slot_inst_get (insn) == 1) + return OPCODE_RFDD; + } + } + if (Field_op1_Slot_inst_get (insn) == 2) + { + if (Field_op2_Slot_inst_get (insn) == 0) + return OPCODE_ANDB; + if (Field_op2_Slot_inst_get (insn) == 1) + return OPCODE_ANDBC; + if (Field_op2_Slot_inst_get (insn) == 2) + return OPCODE_ORB; + if (Field_op2_Slot_inst_get (insn) == 3) + return OPCODE_ORBC; + if (Field_op2_Slot_inst_get (insn) == 4) + return OPCODE_XORB; + if (Field_op2_Slot_inst_get (insn) == 8) + return OPCODE_MULL; + if (Field_op2_Slot_inst_get (insn) == 10) + return OPCODE_MULUH; + if (Field_op2_Slot_inst_get (insn) == 11) + return OPCODE_MULSH; + if (Field_op2_Slot_inst_get (insn) == 12) + return OPCODE_QUOU; + if (Field_op2_Slot_inst_get (insn) == 13) + return OPCODE_QUOS; + if (Field_op2_Slot_inst_get (insn) == 14) + return OPCODE_REMU; + if (Field_op2_Slot_inst_get (insn) == 15) + return OPCODE_REMS; + } + if (Field_op1_Slot_inst_get (insn) == 3) + { + if (Field_op2_Slot_inst_get (insn) == 0) + { + if (Field_sr_Slot_inst_get (insn) == 0) + return OPCODE_RSR_LBEG; + if (Field_sr_Slot_inst_get (insn) == 1) + return OPCODE_RSR_LEND; + if (Field_sr_Slot_inst_get (insn) == 2) + return OPCODE_RSR_LCOUNT; + if (Field_sr_Slot_inst_get (insn) == 3) + return OPCODE_RSR_SAR; + if (Field_sr_Slot_inst_get (insn) == 4) + return OPCODE_RSR_BR; + if (Field_sr_Slot_inst_get (insn) == 5) + return OPCODE_RSR_LITBASE; + if (Field_sr_Slot_inst_get (insn) == 12) + return OPCODE_RSR_SCOMPARE1; + if (Field_sr_Slot_inst_get (insn) == 16) + return OPCODE_RSR_ACCLO; + if (Field_sr_Slot_inst_get (insn) == 17) + return OPCODE_RSR_ACCHI; + if (Field_sr_Slot_inst_get (insn) == 32) + return OPCODE_RSR_M0; + if (Field_sr_Slot_inst_get (insn) == 33) + return OPCODE_RSR_M1; + if (Field_sr_Slot_inst_get (insn) == 34) + return OPCODE_RSR_M2; + if (Field_sr_Slot_inst_get (insn) == 35) + return OPCODE_RSR_M3; + if (Field_sr_Slot_inst_get (insn) == 72) + return OPCODE_RSR_WINDOWBASE; + if (Field_sr_Slot_inst_get (insn) == 73) + return OPCODE_RSR_WINDOWSTART; + if (Field_sr_Slot_inst_get (insn) == 96) + return OPCODE_RSR_IBREAKENABLE; + if (Field_sr_Slot_inst_get (insn) == 97) + return OPCODE_RSR_MEMCTL; + if (Field_sr_Slot_inst_get (insn) == 99) + return OPCODE_RSR_ATOMCTL; + if (Field_sr_Slot_inst_get (insn) == 104) + return OPCODE_RSR_DDR; + if (Field_sr_Slot_inst_get (insn) == 128) + return OPCODE_RSR_IBREAKA0; + if (Field_sr_Slot_inst_get (insn) == 129) + return OPCODE_RSR_IBREAKA1; + if (Field_sr_Slot_inst_get (insn) == 144) + return OPCODE_RSR_DBREAKA0; + if (Field_sr_Slot_inst_get (insn) == 145) + return OPCODE_RSR_DBREAKA1; + if (Field_sr_Slot_inst_get (insn) == 160) + return OPCODE_RSR_DBREAKC0; + if (Field_sr_Slot_inst_get (insn) == 161) + return OPCODE_RSR_DBREAKC1; + if (Field_sr_Slot_inst_get (insn) == 176) + return OPCODE_RSR_CONFIGID0; + if (Field_sr_Slot_inst_get (insn) == 177) + return OPCODE_RSR_EPC1; + if (Field_sr_Slot_inst_get (insn) == 178) + return OPCODE_RSR_EPC2; + if (Field_sr_Slot_inst_get (insn) == 179) + return OPCODE_RSR_EPC3; + if (Field_sr_Slot_inst_get (insn) == 180) + return OPCODE_RSR_EPC4; + if (Field_sr_Slot_inst_get (insn) == 181) + return OPCODE_RSR_EPC5; + if (Field_sr_Slot_inst_get (insn) == 182) + return OPCODE_RSR_EPC6; + if (Field_sr_Slot_inst_get (insn) == 183) + return OPCODE_RSR_EPC7; + if (Field_sr_Slot_inst_get (insn) == 192) + return OPCODE_RSR_DEPC; + if (Field_sr_Slot_inst_get (insn) == 194) + return OPCODE_RSR_EPS2; + if (Field_sr_Slot_inst_get (insn) == 195) + return OPCODE_RSR_EPS3; + if (Field_sr_Slot_inst_get (insn) == 196) + return OPCODE_RSR_EPS4; + if (Field_sr_Slot_inst_get (insn) == 197) + return OPCODE_RSR_EPS5; + if (Field_sr_Slot_inst_get (insn) == 198) + return OPCODE_RSR_EPS6; + if (Field_sr_Slot_inst_get (insn) == 199) + return OPCODE_RSR_EPS7; + if (Field_sr_Slot_inst_get (insn) == 208) + return OPCODE_RSR_CONFIGID1; + if (Field_sr_Slot_inst_get (insn) == 209) + return OPCODE_RSR_EXCSAVE1; + if (Field_sr_Slot_inst_get (insn) == 210) + return OPCODE_RSR_EXCSAVE2; + if (Field_sr_Slot_inst_get (insn) == 211) + return OPCODE_RSR_EXCSAVE3; + if (Field_sr_Slot_inst_get (insn) == 212) + return OPCODE_RSR_EXCSAVE4; + if (Field_sr_Slot_inst_get (insn) == 213) + return OPCODE_RSR_EXCSAVE5; + if (Field_sr_Slot_inst_get (insn) == 214) + return OPCODE_RSR_EXCSAVE6; + if (Field_sr_Slot_inst_get (insn) == 215) + return OPCODE_RSR_EXCSAVE7; + if (Field_sr_Slot_inst_get (insn) == 224) + return OPCODE_RSR_CPENABLE; + if (Field_sr_Slot_inst_get (insn) == 226) + return OPCODE_RSR_INTERRUPT; + if (Field_sr_Slot_inst_get (insn) == 228) + return OPCODE_RSR_INTENABLE; + if (Field_sr_Slot_inst_get (insn) == 230) + return OPCODE_RSR_PS; + if (Field_sr_Slot_inst_get (insn) == 231) + return OPCODE_RSR_VECBASE; + if (Field_sr_Slot_inst_get (insn) == 232) + return OPCODE_RSR_EXCCAUSE; + if (Field_sr_Slot_inst_get (insn) == 233) + return OPCODE_RSR_DEBUGCAUSE; + if (Field_sr_Slot_inst_get (insn) == 234) + return OPCODE_RSR_CCOUNT; + if (Field_sr_Slot_inst_get (insn) == 235) + return OPCODE_RSR_PRID; + if (Field_sr_Slot_inst_get (insn) == 236) + return OPCODE_RSR_ICOUNT; + if (Field_sr_Slot_inst_get (insn) == 237) + return OPCODE_RSR_ICOUNTLEVEL; + if (Field_sr_Slot_inst_get (insn) == 238) + return OPCODE_RSR_EXCVADDR; + if (Field_sr_Slot_inst_get (insn) == 240) + return OPCODE_RSR_CCOMPARE0; + if (Field_sr_Slot_inst_get (insn) == 241) + return OPCODE_RSR_CCOMPARE1; + if (Field_sr_Slot_inst_get (insn) == 242) + return OPCODE_RSR_CCOMPARE2; + if (Field_sr_Slot_inst_get (insn) == 244) + return OPCODE_RSR_MISC0; + if (Field_sr_Slot_inst_get (insn) == 245) + return OPCODE_RSR_MISC1; + if (Field_sr_Slot_inst_get (insn) == 246) + return OPCODE_RSR_MISC2; + if (Field_sr_Slot_inst_get (insn) == 247) + return OPCODE_RSR_MISC3; + } + if (Field_op2_Slot_inst_get (insn) == 1) + { + if (Field_sr_Slot_inst_get (insn) == 0) + return OPCODE_WSR_LBEG; + if (Field_sr_Slot_inst_get (insn) == 1) + return OPCODE_WSR_LEND; + if (Field_sr_Slot_inst_get (insn) == 2) + return OPCODE_WSR_LCOUNT; + if (Field_sr_Slot_inst_get (insn) == 3) + return OPCODE_WSR_SAR; + if (Field_sr_Slot_inst_get (insn) == 4) + return OPCODE_WSR_BR; + if (Field_sr_Slot_inst_get (insn) == 5) + return OPCODE_WSR_LITBASE; + if (Field_sr_Slot_inst_get (insn) == 12) + return OPCODE_WSR_SCOMPARE1; + if (Field_sr_Slot_inst_get (insn) == 16) + return OPCODE_WSR_ACCLO; + if (Field_sr_Slot_inst_get (insn) == 17) + return OPCODE_WSR_ACCHI; + if (Field_sr_Slot_inst_get (insn) == 32) + return OPCODE_WSR_M0; + if (Field_sr_Slot_inst_get (insn) == 33) + return OPCODE_WSR_M1; + if (Field_sr_Slot_inst_get (insn) == 34) + return OPCODE_WSR_M2; + if (Field_sr_Slot_inst_get (insn) == 35) + return OPCODE_WSR_M3; + if (Field_sr_Slot_inst_get (insn) == 72) + return OPCODE_WSR_WINDOWBASE; + if (Field_sr_Slot_inst_get (insn) == 73) + return OPCODE_WSR_WINDOWSTART; + if (Field_sr_Slot_inst_get (insn) == 89) + return OPCODE_WSR_MMID; + if (Field_sr_Slot_inst_get (insn) == 96) + return OPCODE_WSR_IBREAKENABLE; + if (Field_sr_Slot_inst_get (insn) == 97) + return OPCODE_WSR_MEMCTL; + if (Field_sr_Slot_inst_get (insn) == 99) + return OPCODE_WSR_ATOMCTL; + if (Field_sr_Slot_inst_get (insn) == 104) + return OPCODE_WSR_DDR; + if (Field_sr_Slot_inst_get (insn) == 128) + return OPCODE_WSR_IBREAKA0; + if (Field_sr_Slot_inst_get (insn) == 129) + return OPCODE_WSR_IBREAKA1; + if (Field_sr_Slot_inst_get (insn) == 144) + return OPCODE_WSR_DBREAKA0; + if (Field_sr_Slot_inst_get (insn) == 145) + return OPCODE_WSR_DBREAKA1; + if (Field_sr_Slot_inst_get (insn) == 160) + return OPCODE_WSR_DBREAKC0; + if (Field_sr_Slot_inst_get (insn) == 161) + return OPCODE_WSR_DBREAKC1; + if (Field_sr_Slot_inst_get (insn) == 176) + return OPCODE_WSR_CONFIGID0; + if (Field_sr_Slot_inst_get (insn) == 177) + return OPCODE_WSR_EPC1; + if (Field_sr_Slot_inst_get (insn) == 178) + return OPCODE_WSR_EPC2; + if (Field_sr_Slot_inst_get (insn) == 179) + return OPCODE_WSR_EPC3; + if (Field_sr_Slot_inst_get (insn) == 180) + return OPCODE_WSR_EPC4; + if (Field_sr_Slot_inst_get (insn) == 181) + return OPCODE_WSR_EPC5; + if (Field_sr_Slot_inst_get (insn) == 182) + return OPCODE_WSR_EPC6; + if (Field_sr_Slot_inst_get (insn) == 183) + return OPCODE_WSR_EPC7; + if (Field_sr_Slot_inst_get (insn) == 192) + return OPCODE_WSR_DEPC; + if (Field_sr_Slot_inst_get (insn) == 194) + return OPCODE_WSR_EPS2; + if (Field_sr_Slot_inst_get (insn) == 195) + return OPCODE_WSR_EPS3; + if (Field_sr_Slot_inst_get (insn) == 196) + return OPCODE_WSR_EPS4; + if (Field_sr_Slot_inst_get (insn) == 197) + return OPCODE_WSR_EPS5; + if (Field_sr_Slot_inst_get (insn) == 198) + return OPCODE_WSR_EPS6; + if (Field_sr_Slot_inst_get (insn) == 199) + return OPCODE_WSR_EPS7; + if (Field_sr_Slot_inst_get (insn) == 209) + return OPCODE_WSR_EXCSAVE1; + if (Field_sr_Slot_inst_get (insn) == 210) + return OPCODE_WSR_EXCSAVE2; + if (Field_sr_Slot_inst_get (insn) == 211) + return OPCODE_WSR_EXCSAVE3; + if (Field_sr_Slot_inst_get (insn) == 212) + return OPCODE_WSR_EXCSAVE4; + if (Field_sr_Slot_inst_get (insn) == 213) + return OPCODE_WSR_EXCSAVE5; + if (Field_sr_Slot_inst_get (insn) == 214) + return OPCODE_WSR_EXCSAVE6; + if (Field_sr_Slot_inst_get (insn) == 215) + return OPCODE_WSR_EXCSAVE7; + if (Field_sr_Slot_inst_get (insn) == 224) + return OPCODE_WSR_CPENABLE; + if (Field_sr_Slot_inst_get (insn) == 226) + return OPCODE_WSR_INTSET; + if (Field_sr_Slot_inst_get (insn) == 227) + return OPCODE_WSR_INTCLEAR; + if (Field_sr_Slot_inst_get (insn) == 228) + return OPCODE_WSR_INTENABLE; + if (Field_sr_Slot_inst_get (insn) == 230) + return OPCODE_WSR_PS; + if (Field_sr_Slot_inst_get (insn) == 231) + return OPCODE_WSR_VECBASE; + if (Field_sr_Slot_inst_get (insn) == 232) + return OPCODE_WSR_EXCCAUSE; + if (Field_sr_Slot_inst_get (insn) == 233) + return OPCODE_WSR_DEBUGCAUSE; + if (Field_sr_Slot_inst_get (insn) == 234) + return OPCODE_WSR_CCOUNT; + if (Field_sr_Slot_inst_get (insn) == 236) + return OPCODE_WSR_ICOUNT; + if (Field_sr_Slot_inst_get (insn) == 237) + return OPCODE_WSR_ICOUNTLEVEL; + if (Field_sr_Slot_inst_get (insn) == 238) + return OPCODE_WSR_EXCVADDR; + if (Field_sr_Slot_inst_get (insn) == 240) + return OPCODE_WSR_CCOMPARE0; + if (Field_sr_Slot_inst_get (insn) == 241) + return OPCODE_WSR_CCOMPARE1; + if (Field_sr_Slot_inst_get (insn) == 242) + return OPCODE_WSR_CCOMPARE2; + if (Field_sr_Slot_inst_get (insn) == 244) + return OPCODE_WSR_MISC0; + if (Field_sr_Slot_inst_get (insn) == 245) + return OPCODE_WSR_MISC1; + if (Field_sr_Slot_inst_get (insn) == 246) + return OPCODE_WSR_MISC2; + if (Field_sr_Slot_inst_get (insn) == 247) + return OPCODE_WSR_MISC3; + } + if (Field_op2_Slot_inst_get (insn) == 2) + return OPCODE_SEXT; + if (Field_op2_Slot_inst_get (insn) == 3) + return OPCODE_CLAMPS; + if (Field_op2_Slot_inst_get (insn) == 4) + return OPCODE_MIN; + if (Field_op2_Slot_inst_get (insn) == 5) + return OPCODE_MAX; + if (Field_op2_Slot_inst_get (insn) == 6) + return OPCODE_MINU; + if (Field_op2_Slot_inst_get (insn) == 7) + return OPCODE_MAXU; + if (Field_op2_Slot_inst_get (insn) == 8) + return OPCODE_MOVEQZ; + if (Field_op2_Slot_inst_get (insn) == 9) + return OPCODE_MOVNEZ; + if (Field_op2_Slot_inst_get (insn) == 10) + return OPCODE_MOVLTZ; + if (Field_op2_Slot_inst_get (insn) == 11) + return OPCODE_MOVGEZ; + if (Field_op2_Slot_inst_get (insn) == 12) + return OPCODE_MOVF; + if (Field_op2_Slot_inst_get (insn) == 13) + return OPCODE_MOVT; + if (Field_op2_Slot_inst_get (insn) == 14) + { + if (Field_st_Slot_inst_get (insn) == 230) + return OPCODE_RUR_EXPSTATE; + if (Field_st_Slot_inst_get (insn) == 231) + return OPCODE_RUR_THREADPTR; + if (Field_st_Slot_inst_get (insn) == 232) + return OPCODE_RUR_FCR; + if (Field_st_Slot_inst_get (insn) == 233) + return OPCODE_RUR_FSR; + if (Field_st_Slot_inst_get (insn) == 234) + return OPCODE_RUR_F64R_LO; + if (Field_st_Slot_inst_get (insn) == 235) + return OPCODE_RUR_F64R_HI; + if (Field_st_Slot_inst_get (insn) == 236) + return OPCODE_RUR_F64S; + } + if (Field_op2_Slot_inst_get (insn) == 15) + { + if (Field_sr_Slot_inst_get (insn) == 230) + return OPCODE_WUR_EXPSTATE; + if (Field_sr_Slot_inst_get (insn) == 231) + return OPCODE_WUR_THREADPTR; + if (Field_sr_Slot_inst_get (insn) == 232) + return OPCODE_WUR_FCR; + if (Field_sr_Slot_inst_get (insn) == 233) + return OPCODE_WUR_FSR; + if (Field_sr_Slot_inst_get (insn) == 234) + return OPCODE_WUR_F64R_LO; + if (Field_sr_Slot_inst_get (insn) == 235) + return OPCODE_WUR_F64R_HI; + if (Field_sr_Slot_inst_get (insn) == 236) + return OPCODE_WUR_F64S; + } + } + if ((Field_op1_Slot_inst_get (insn) == 4 || + Field_op1_Slot_inst_get (insn) == 5)) + return OPCODE_EXTUI; + if (Field_op1_Slot_inst_get (insn) == 8) + { + if (Field_op2_Slot_inst_get (insn) == 0) + return OPCODE_LSX; + if (Field_op2_Slot_inst_get (insn) == 1) + return OPCODE_LSXP; + if (Field_op2_Slot_inst_get (insn) == 4) + return OPCODE_SSX; + if (Field_op2_Slot_inst_get (insn) == 5) + return OPCODE_SSXP; + } + if (Field_op1_Slot_inst_get (insn) == 9) + { + if (Field_op2_Slot_inst_get (insn) == 0) + return OPCODE_L32E; + if (Field_op2_Slot_inst_get (insn) == 4) + return OPCODE_S32E; + if (Field_op2_Slot_inst_get (insn) == 5) + return OPCODE_S32NB; + } + if (Field_op1_Slot_inst_get (insn) == 10) + { + if (Field_op2_Slot_inst_get (insn) == 0) + return OPCODE_ADD_S; + if (Field_op2_Slot_inst_get (insn) == 1) + return OPCODE_SUB_S; + if (Field_op2_Slot_inst_get (insn) == 2) + return OPCODE_MUL_S; + if (Field_op2_Slot_inst_get (insn) == 4) + return OPCODE_MADD_S; + if (Field_op2_Slot_inst_get (insn) == 5) + return OPCODE_MSUB_S; + if (Field_op2_Slot_inst_get (insn) == 6) + return OPCODE_MADDN_S; + if (Field_op2_Slot_inst_get (insn) == 7) + return OPCODE_DIVN_S; + if (Field_op2_Slot_inst_get (insn) == 8) + return OPCODE_ROUND_S; + if (Field_op2_Slot_inst_get (insn) == 9) + return OPCODE_TRUNC_S; + if (Field_op2_Slot_inst_get (insn) == 10) + return OPCODE_FLOOR_S; + if (Field_op2_Slot_inst_get (insn) == 11) + return OPCODE_CEIL_S; + if (Field_op2_Slot_inst_get (insn) == 12) + return OPCODE_FLOAT_S; + if (Field_op2_Slot_inst_get (insn) == 13) + return OPCODE_UFLOAT_S; + if (Field_op2_Slot_inst_get (insn) == 14) + return OPCODE_UTRUNC_S; + if (Field_op2_Slot_inst_get (insn) == 15) + { + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_MOV_S; + if (Field_t_Slot_inst_get (insn) == 1) + return OPCODE_ABS_S; + if (Field_t_Slot_inst_get (insn) == 3) + return OPCODE_CONST_S; + if (Field_t_Slot_inst_get (insn) == 4) + return OPCODE_RFR; + if (Field_t_Slot_inst_get (insn) == 5) + return OPCODE_WFR; + if (Field_t_Slot_inst_get (insn) == 6) + return OPCODE_NEG_S; + if (Field_t_Slot_inst_get (insn) == 7) + return OPCODE_DIV0_S; + if (Field_t_Slot_inst_get (insn) == 8) + return OPCODE_RECIP0_S; + if (Field_t_Slot_inst_get (insn) == 9) + return OPCODE_SQRT0_S; + if (Field_t_Slot_inst_get (insn) == 10) + return OPCODE_RSQRT0_S; + if (Field_t_Slot_inst_get (insn) == 11) + return OPCODE_NEXP01_S; + if (Field_t_Slot_inst_get (insn) == 12) + return OPCODE_MKSADJ_S; + if (Field_t_Slot_inst_get (insn) == 13) + return OPCODE_MKDADJ_S; + if (Field_t_Slot_inst_get (insn) == 14) + return OPCODE_ADDEXP_S; + if (Field_t_Slot_inst_get (insn) == 15) + return OPCODE_ADDEXPM_S; + } + } + if (Field_op1_Slot_inst_get (insn) == 11) + { + if (Field_op2_Slot_inst_get (insn) == 1) + return OPCODE_UN_S; + if (Field_op2_Slot_inst_get (insn) == 2) + return OPCODE_OEQ_S; + if (Field_op2_Slot_inst_get (insn) == 3) + return OPCODE_UEQ_S; + if (Field_op2_Slot_inst_get (insn) == 4) + return OPCODE_OLT_S; + if (Field_op2_Slot_inst_get (insn) == 5) + return OPCODE_ULT_S; + if (Field_op2_Slot_inst_get (insn) == 6) + return OPCODE_OLE_S; + if (Field_op2_Slot_inst_get (insn) == 7) + return OPCODE_ULE_S; + if (Field_op2_Slot_inst_get (insn) == 8) + return OPCODE_MOVEQZ_S; + if (Field_op2_Slot_inst_get (insn) == 9) + return OPCODE_MOVNEZ_S; + if (Field_op2_Slot_inst_get (insn) == 10) + return OPCODE_MOVLTZ_S; + if (Field_op2_Slot_inst_get (insn) == 11) + return OPCODE_MOVGEZ_S; + if (Field_op2_Slot_inst_get (insn) == 12) + return OPCODE_MOVF_S; + if (Field_op2_Slot_inst_get (insn) == 13) + return OPCODE_MOVT_S; + } + if (Field_r_Slot_inst_get (insn) == 0 && + Field_s_Slot_inst_get (insn) == 0 && + Field_op2_Slot_inst_get (insn) == 0 && + Field_op1_Slot_inst_get (insn) == 14) + return OPCODE_READ_IMPWIRE; + if (Field_r_Slot_inst_get (insn) == 1 && + Field_s3to1_Slot_inst_get (insn) == 0 && + Field_op2_Slot_inst_get (insn) == 0 && + Field_op1_Slot_inst_get (insn) == 14) + return OPCODE_SETB_EXPSTATE; + if (Field_r_Slot_inst_get (insn) == 1 && + Field_s3to1_Slot_inst_get (insn) == 1 && + Field_op2_Slot_inst_get (insn) == 0 && + Field_op1_Slot_inst_get (insn) == 14) + return OPCODE_CLRB_EXPSTATE; + if (Field_r_Slot_inst_get (insn) == 2 && + Field_op2_Slot_inst_get (insn) == 0 && + Field_op1_Slot_inst_get (insn) == 14) + return OPCODE_WRMSK_EXPSTATE; + } + if (Field_op0_Slot_inst_get (insn) == 0) + { + if (Field_dfp_fld_op1_Slot_inst_get (insn) == 11) + { + if (Field_dfp_fld_op2_Slot_inst_get (insn) == 0) + { + if (Field_dfp_fld_r_3_1_Slot_inst_get (insn) == 7) + return OPCODE_WF64R; + if (Field_dfp_fld_s_3_1_Slot_inst_get (insn) == 7 && + Field_r_Slot_inst_get (insn) == 12) + return OPCODE_RF64R; + } + if (Field_dfp_fld_op2_Slot_inst_get (insn) == 14) + { + return OPCODE_F64CMPL; + } + if (Field_dfp_fld_op2_Slot_inst_get (insn) == 15) + { + if (Field_dfp_fld_r_3_Slot_inst_get (insn) == 0) + return OPCODE_F64ADDC; + if (Field_dfp_fld_r_3_Slot_inst_get (insn) == 1) + return OPCODE_F64SUBC; + } + } + if (Field_dfp_fld_op1_Slot_inst_get (insn) == 14) + { + if (Field_dfp_fld_op2_Slot_inst_get (insn) == 0) + { + if (Field_r_Slot_inst_get (insn) == 13) + return OPCODE_F64SIG; + } + if (Field_dfp_fld_op2_Slot_inst_get (insn) == 1) + { + return OPCODE_F64SEXP; + } + if (Field_dfp_fld_op2_3_Slot_inst_get (insn) == 1) + return OPCODE_F64ITER; + if (Field_dfp_fld_op2_3_1_Slot_inst_get (insn) == 1) + return OPCODE_F64NORM; + if (Field_dfp_fld_op2_3_2_Slot_inst_get (insn) == 1) + return OPCODE_F64RND; + } + if (Field_dfp_fld_op1_Slot_inst_get (insn) == 15) + { + return OPCODE_F64CMPH; + } + } + if (Field_op0_Slot_inst_get (insn) == 1) + return OPCODE_L32R; + if (Field_op0_Slot_inst_get (insn) == 2) + { + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_L8UI; + if (Field_r_Slot_inst_get (insn) == 1) + return OPCODE_L16UI; + if (Field_r_Slot_inst_get (insn) == 2) + return OPCODE_L32I; + if (Field_r_Slot_inst_get (insn) == 4) + return OPCODE_S8I; + if (Field_r_Slot_inst_get (insn) == 5) + return OPCODE_S16I; + if (Field_r_Slot_inst_get (insn) == 6) + return OPCODE_S32I; + if (Field_r_Slot_inst_get (insn) == 9) + return OPCODE_L16SI; + if (Field_r_Slot_inst_get (insn) == 10) + return OPCODE_MOVI; + if (Field_r_Slot_inst_get (insn) == 11) + return OPCODE_L32AI; + if (Field_r_Slot_inst_get (insn) == 12) + return OPCODE_ADDI; + if (Field_r_Slot_inst_get (insn) == 13) + return OPCODE_ADDMI; + if (Field_r_Slot_inst_get (insn) == 14) + return OPCODE_S32C1I; + if (Field_r_Slot_inst_get (insn) == 15) + return OPCODE_S32RI; + } + if (Field_op0_Slot_inst_get (insn) == 3) + { + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_LSI; + if (Field_r_Slot_inst_get (insn) == 4) + return OPCODE_SSI; + if (Field_r_Slot_inst_get (insn) == 8) + return OPCODE_LSIP; + if (Field_r_Slot_inst_get (insn) == 12) + return OPCODE_SSIP; + } + if (Field_op0_Slot_inst_get (insn) == 4) + { + if (Field_op2_Slot_inst_get (insn) == 0) + { + if (Field_op1_Slot_inst_get (insn) == 8 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_LL_LDINC; + if (Field_op1_Slot_inst_get (insn) == 9 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_HL_LDINC; + if (Field_op1_Slot_inst_get (insn) == 10 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_LH_LDINC; + if (Field_op1_Slot_inst_get (insn) == 11 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_HH_LDINC; + } + if (Field_op2_Slot_inst_get (insn) == 1) + { + if (Field_op1_Slot_inst_get (insn) == 8 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_LL_LDDEC; + if (Field_op1_Slot_inst_get (insn) == 9 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_HL_LDDEC; + if (Field_op1_Slot_inst_get (insn) == 10 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_LH_LDDEC; + if (Field_op1_Slot_inst_get (insn) == 11 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_HH_LDDEC; + } + if (Field_op2_Slot_inst_get (insn) == 2) + { + if (Field_op1_Slot_inst_get (insn) == 4 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DD_LL; + if (Field_op1_Slot_inst_get (insn) == 5 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DD_HL; + if (Field_op1_Slot_inst_get (insn) == 6 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DD_LH; + if (Field_op1_Slot_inst_get (insn) == 7 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DD_HH; + if (Field_op1_Slot_inst_get (insn) == 8 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_LL; + if (Field_op1_Slot_inst_get (insn) == 9 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_HL; + if (Field_op1_Slot_inst_get (insn) == 10 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_LH; + if (Field_op1_Slot_inst_get (insn) == 11 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_HH; + if (Field_op1_Slot_inst_get (insn) == 12 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DD_LL; + if (Field_op1_Slot_inst_get (insn) == 13 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DD_HL; + if (Field_op1_Slot_inst_get (insn) == 14 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DD_LH; + if (Field_op1_Slot_inst_get (insn) == 15 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DD_HH; + } + if (Field_op2_Slot_inst_get (insn) == 3) + { + if (Field_op1_Slot_inst_get (insn) == 4 && + Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AD_LL; + if (Field_op1_Slot_inst_get (insn) == 5 && + Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AD_HL; + if (Field_op1_Slot_inst_get (insn) == 6 && + Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AD_LH; + if (Field_op1_Slot_inst_get (insn) == 7 && + Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AD_HH; + if (Field_op1_Slot_inst_get (insn) == 8 && + Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AD_LL; + if (Field_op1_Slot_inst_get (insn) == 9 && + Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AD_HL; + if (Field_op1_Slot_inst_get (insn) == 10 && + Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AD_LH; + if (Field_op1_Slot_inst_get (insn) == 11 && + Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AD_HH; + if (Field_op1_Slot_inst_get (insn) == 12 && + Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AD_LL; + if (Field_op1_Slot_inst_get (insn) == 13 && + Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AD_HL; + if (Field_op1_Slot_inst_get (insn) == 14 && + Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AD_LH; + if (Field_op1_Slot_inst_get (insn) == 15 && + Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AD_HH; + } + if (Field_op2_Slot_inst_get (insn) == 4) + { + if (Field_op1_Slot_inst_get (insn) == 8 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_LL_LDINC; + if (Field_op1_Slot_inst_get (insn) == 9 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_HL_LDINC; + if (Field_op1_Slot_inst_get (insn) == 10 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_LH_LDINC; + if (Field_op1_Slot_inst_get (insn) == 11 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_HH_LDINC; + } + if (Field_op2_Slot_inst_get (insn) == 5) + { + if (Field_op1_Slot_inst_get (insn) == 8 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_LL_LDDEC; + if (Field_op1_Slot_inst_get (insn) == 9 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_HL_LDDEC; + if (Field_op1_Slot_inst_get (insn) == 10 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_LH_LDDEC; + if (Field_op1_Slot_inst_get (insn) == 11 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_HH_LDDEC; + } + if (Field_op2_Slot_inst_get (insn) == 6) + { + if (Field_op1_Slot_inst_get (insn) == 4 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DA_LL; + if (Field_op1_Slot_inst_get (insn) == 5 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DA_HL; + if (Field_op1_Slot_inst_get (insn) == 6 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DA_LH; + if (Field_op1_Slot_inst_get (insn) == 7 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DA_HH; + if (Field_op1_Slot_inst_get (insn) == 8 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_LL; + if (Field_op1_Slot_inst_get (insn) == 9 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_HL; + if (Field_op1_Slot_inst_get (insn) == 10 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_LH; + if (Field_op1_Slot_inst_get (insn) == 11 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_HH; + if (Field_op1_Slot_inst_get (insn) == 12 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DA_LL; + if (Field_op1_Slot_inst_get (insn) == 13 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DA_HL; + if (Field_op1_Slot_inst_get (insn) == 14 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DA_LH; + if (Field_op1_Slot_inst_get (insn) == 15 && + Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DA_HH; + } + if (Field_op2_Slot_inst_get (insn) == 7) + { + if (Field_op1_Slot_inst_get (insn) == 0 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_UMUL_AA_LL; + if (Field_op1_Slot_inst_get (insn) == 1 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_UMUL_AA_HL; + if (Field_op1_Slot_inst_get (insn) == 2 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_UMUL_AA_LH; + if (Field_op1_Slot_inst_get (insn) == 3 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_UMUL_AA_HH; + if (Field_op1_Slot_inst_get (insn) == 4 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AA_LL; + if (Field_op1_Slot_inst_get (insn) == 5 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AA_HL; + if (Field_op1_Slot_inst_get (insn) == 6 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AA_LH; + if (Field_op1_Slot_inst_get (insn) == 7 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AA_HH; + if (Field_op1_Slot_inst_get (insn) == 8 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AA_LL; + if (Field_op1_Slot_inst_get (insn) == 9 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AA_HL; + if (Field_op1_Slot_inst_get (insn) == 10 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AA_LH; + if (Field_op1_Slot_inst_get (insn) == 11 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AA_HH; + if (Field_op1_Slot_inst_get (insn) == 12 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AA_LL; + if (Field_op1_Slot_inst_get (insn) == 13 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AA_HL; + if (Field_op1_Slot_inst_get (insn) == 14 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AA_LH; + if (Field_op1_Slot_inst_get (insn) == 15 && + Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AA_HH; + } + if (Field_op2_Slot_inst_get (insn) == 8) + { + if (Field_op1_Slot_inst_get (insn) == 0 && + Field_t_Slot_inst_get (insn) == 0 && + Field_rhi_Slot_inst_get (insn) == 0) + return OPCODE_LDINC; + } + if (Field_op2_Slot_inst_get (insn) == 9) + { + if (Field_op1_Slot_inst_get (insn) == 0 && + Field_t_Slot_inst_get (insn) == 0 && + Field_rhi_Slot_inst_get (insn) == 0) + return OPCODE_LDDEC; + } + } + if (Field_op0_Slot_inst_get (insn) == 5) + { + if (Field_n_Slot_inst_get (insn) == 0) + return OPCODE_CALL0; + if (Field_n_Slot_inst_get (insn) == 1) + return OPCODE_CALL4; + if (Field_n_Slot_inst_get (insn) == 2) + return OPCODE_CALL8; + if (Field_n_Slot_inst_get (insn) == 3) + return OPCODE_CALL12; + } + if (Field_op0_Slot_inst_get (insn) == 6) + { + if (Field_n_Slot_inst_get (insn) == 0) + return OPCODE_J; + if (Field_n_Slot_inst_get (insn) == 1) + { + if (Field_m_Slot_inst_get (insn) == 0) + return OPCODE_BEQZ; + if (Field_m_Slot_inst_get (insn) == 1) + return OPCODE_BNEZ; + if (Field_m_Slot_inst_get (insn) == 2) + return OPCODE_BLTZ; + if (Field_m_Slot_inst_get (insn) == 3) + return OPCODE_BGEZ; + } + if (Field_n_Slot_inst_get (insn) == 2) + { + if (Field_m_Slot_inst_get (insn) == 0) + return OPCODE_BEQI; + if (Field_m_Slot_inst_get (insn) == 1) + return OPCODE_BNEI; + if (Field_m_Slot_inst_get (insn) == 2) + return OPCODE_BLTI; + if (Field_m_Slot_inst_get (insn) == 3) + return OPCODE_BGEI; + } + if (Field_n_Slot_inst_get (insn) == 3) + { + if (Field_m_Slot_inst_get (insn) == 0) + return OPCODE_ENTRY; + if (Field_m_Slot_inst_get (insn) == 1) + { + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_BF; + if (Field_r_Slot_inst_get (insn) == 1) + return OPCODE_BT; + if (Field_r_Slot_inst_get (insn) == 8) + return OPCODE_LOOP; + if (Field_r_Slot_inst_get (insn) == 9) + return OPCODE_LOOPNEZ; + if (Field_r_Slot_inst_get (insn) == 10) + return OPCODE_LOOPGTZ; + } + if (Field_m_Slot_inst_get (insn) == 2) + return OPCODE_BLTUI; + if (Field_m_Slot_inst_get (insn) == 3) + return OPCODE_BGEUI; + } + } + if (Field_op0_Slot_inst_get (insn) == 7) + { + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_BNONE; + if (Field_r_Slot_inst_get (insn) == 1) + return OPCODE_BEQ; + if (Field_r_Slot_inst_get (insn) == 2) + return OPCODE_BLT; + if (Field_r_Slot_inst_get (insn) == 3) + return OPCODE_BLTU; + if (Field_r_Slot_inst_get (insn) == 4) + return OPCODE_BALL; + if (Field_r_Slot_inst_get (insn) == 5) + return OPCODE_BBC; + if ((Field_r_Slot_inst_get (insn) == 6 || + Field_r_Slot_inst_get (insn) == 7)) + return OPCODE_BBCI; + if (Field_r_Slot_inst_get (insn) == 8) + return OPCODE_BANY; + if (Field_r_Slot_inst_get (insn) == 9) + return OPCODE_BNE; + if (Field_r_Slot_inst_get (insn) == 10) + return OPCODE_BGE; + if (Field_r_Slot_inst_get (insn) == 11) + return OPCODE_BGEU; + if (Field_r_Slot_inst_get (insn) == 12) + return OPCODE_BNALL; + if (Field_r_Slot_inst_get (insn) == 13) + return OPCODE_BBS; + if ((Field_r_Slot_inst_get (insn) == 14 || + Field_r_Slot_inst_get (insn) == 15)) + return OPCODE_BBSI; + } + return XTENSA_UNDEFINED; +} + +static int +Slot_inst16b_decode (const xtensa_insnbuf insn) +{ + if (Field_op0_Slot_inst16b_get (insn) == 12) + { + if (Field_i_Slot_inst16b_get (insn) == 0) + return OPCODE_MOVI_N; + if (Field_i_Slot_inst16b_get (insn) == 1) + { + if (Field_z_Slot_inst16b_get (insn) == 0) + return OPCODE_BEQZ_N; + if (Field_z_Slot_inst16b_get (insn) == 1) + return OPCODE_BNEZ_N; + } + } + if (Field_op0_Slot_inst16b_get (insn) == 13) + { + if (Field_r_Slot_inst16b_get (insn) == 0) + return OPCODE_MOV_N; + if (Field_r_Slot_inst16b_get (insn) == 15) + { + if (Field_t_Slot_inst16b_get (insn) == 0) + return OPCODE_RET_N; + if (Field_t_Slot_inst16b_get (insn) == 1) + return OPCODE_RETW_N; + if (Field_t_Slot_inst16b_get (insn) == 2) + return OPCODE_BREAK_N; + if (Field_t_Slot_inst16b_get (insn) == 3 && + Field_s_Slot_inst16b_get (insn) == 0) + return OPCODE_NOP_N; + if (Field_t_Slot_inst16b_get (insn) == 6 && + Field_s_Slot_inst16b_get (insn) == 0) + return OPCODE_ILL_N; + } + } + return XTENSA_UNDEFINED; +} + +static int +Slot_inst16a_decode (const xtensa_insnbuf insn) +{ + if (Field_op0_Slot_inst16a_get (insn) == 8) + return OPCODE_L32I_N; + if (Field_op0_Slot_inst16a_get (insn) == 9) + return OPCODE_S32I_N; + if (Field_op0_Slot_inst16a_get (insn) == 10) + return OPCODE_ADD_N; + if (Field_op0_Slot_inst16a_get (insn) == 11) + return OPCODE_ADDI_N; + return XTENSA_UNDEFINED; +} + + +/* Instruction slots. */ + +static void +Slot_x24_Format_inst_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffffff); +} + +static void +Slot_x24_Format_inst_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffffff) | (slotbuf[0] & 0xffffff); +} + +static void +Slot_x16a_Format_inst16a_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffff); +} + +static void +Slot_x16a_Format_inst16a_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffff) | (slotbuf[0] & 0xffff); +} + +static void +Slot_x16b_Format_inst16b_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffff); +} + +static void +Slot_x16b_Format_inst16b_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffff) | (slotbuf[0] & 0xffff); +} + +static xtensa_get_field_fn +Slot_inst_get_field_fns[] = { + Field_t_Slot_inst_get, + Field_bbi4_Slot_inst_get, + Field_bbi_Slot_inst_get, + Field_imm12_Slot_inst_get, + Field_imm8_Slot_inst_get, + Field_s_Slot_inst_get, + Field_imm12b_Slot_inst_get, + Field_imm16_Slot_inst_get, + Field_m_Slot_inst_get, + Field_n_Slot_inst_get, + Field_offset_Slot_inst_get, + Field_op0_Slot_inst_get, + Field_op1_Slot_inst_get, + Field_op2_Slot_inst_get, + Field_r_Slot_inst_get, + Field_sa4_Slot_inst_get, + Field_sae4_Slot_inst_get, + Field_sae_Slot_inst_get, + Field_sal_Slot_inst_get, + Field_sargt_Slot_inst_get, + Field_sas4_Slot_inst_get, + Field_sas_Slot_inst_get, + Field_sr_Slot_inst_get, + Field_st_Slot_inst_get, + Field_thi3_Slot_inst_get, + Field_imm4_Slot_inst_get, + Field_mn_Slot_inst_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_r3_Slot_inst_get, + Field_rbit2_Slot_inst_get, + Field_rhi_Slot_inst_get, + Field_t3_Slot_inst_get, + Field_tbit2_Slot_inst_get, + Field_tlo_Slot_inst_get, + Field_w_Slot_inst_get, + Field_y_Slot_inst_get, + Field_x_Slot_inst_get, + Field_t2_Slot_inst_get, + Field_s2_Slot_inst_get, + Field_r2_Slot_inst_get, + Field_t4_Slot_inst_get, + Field_s4_Slot_inst_get, + Field_r4_Slot_inst_get, + Field_t8_Slot_inst_get, + Field_s8_Slot_inst_get, + Field_r8_Slot_inst_get, + Field_xt_wbr15_imm_Slot_inst_get, + Field_xt_wbr18_imm_Slot_inst_get, + Field_dfp_fld_op1_Slot_inst_get, + Field_dfp_fld_op2_Slot_inst_get, + Field_dfp_fld_r_0_Slot_inst_get, + Field_dfp_fld_r_2_1_Slot_inst_get, + Field_dfp_fld_r_3_Slot_inst_get, + Field_dfp_fld_r_3_1_Slot_inst_get, + Field_dfp_fld_s_0_Slot_inst_get, + Field_dfp_fld_s_3_1_Slot_inst_get, + Field_dfp_fld_op2_0_Slot_inst_get, + Field_dfp_fld_op2_1_0_Slot_inst_get, + Field_dfp_fld_op2_2_Slot_inst_get, + Field_dfp_fld_op2_3_Slot_inst_get, + Field_dfp_fld_op2_3_2_Slot_inst_get, + Field_dfp_fld_op2_3_1_Slot_inst_get, + Field_bitindex_Slot_inst_get, + Field_s3to1_Slot_inst_get, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get, + Implicit_Field_mr0_get, + Implicit_Field_mr1_get, + Implicit_Field_mr2_get, + Implicit_Field_mr3_get, + Implicit_Field_bt16_get, + Implicit_Field_bs16_get, + Implicit_Field_br16_get, + Implicit_Field_brall_get +}; + +static xtensa_set_field_fn +Slot_inst_set_field_fns[] = { + Field_t_Slot_inst_set, + Field_bbi4_Slot_inst_set, + Field_bbi_Slot_inst_set, + Field_imm12_Slot_inst_set, + Field_imm8_Slot_inst_set, + Field_s_Slot_inst_set, + Field_imm12b_Slot_inst_set, + Field_imm16_Slot_inst_set, + Field_m_Slot_inst_set, + Field_n_Slot_inst_set, + Field_offset_Slot_inst_set, + Field_op0_Slot_inst_set, + Field_op1_Slot_inst_set, + Field_op2_Slot_inst_set, + Field_r_Slot_inst_set, + Field_sa4_Slot_inst_set, + Field_sae4_Slot_inst_set, + Field_sae_Slot_inst_set, + Field_sal_Slot_inst_set, + Field_sargt_Slot_inst_set, + Field_sas4_Slot_inst_set, + Field_sas_Slot_inst_set, + Field_sr_Slot_inst_set, + Field_st_Slot_inst_set, + Field_thi3_Slot_inst_set, + Field_imm4_Slot_inst_set, + Field_mn_Slot_inst_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_r3_Slot_inst_set, + Field_rbit2_Slot_inst_set, + Field_rhi_Slot_inst_set, + Field_t3_Slot_inst_set, + Field_tbit2_Slot_inst_set, + Field_tlo_Slot_inst_set, + Field_w_Slot_inst_set, + Field_y_Slot_inst_set, + Field_x_Slot_inst_set, + Field_t2_Slot_inst_set, + Field_s2_Slot_inst_set, + Field_r2_Slot_inst_set, + Field_t4_Slot_inst_set, + Field_s4_Slot_inst_set, + Field_r4_Slot_inst_set, + Field_t8_Slot_inst_set, + Field_s8_Slot_inst_set, + Field_r8_Slot_inst_set, + Field_xt_wbr15_imm_Slot_inst_set, + Field_xt_wbr18_imm_Slot_inst_set, + Field_dfp_fld_op1_Slot_inst_set, + Field_dfp_fld_op2_Slot_inst_set, + Field_dfp_fld_r_0_Slot_inst_set, + Field_dfp_fld_r_2_1_Slot_inst_set, + Field_dfp_fld_r_3_Slot_inst_set, + Field_dfp_fld_r_3_1_Slot_inst_set, + Field_dfp_fld_s_0_Slot_inst_set, + Field_dfp_fld_s_3_1_Slot_inst_set, + Field_dfp_fld_op2_0_Slot_inst_set, + Field_dfp_fld_op2_1_0_Slot_inst_set, + Field_dfp_fld_op2_2_Slot_inst_set, + Field_dfp_fld_op2_3_Slot_inst_set, + Field_dfp_fld_op2_3_2_Slot_inst_set, + Field_dfp_fld_op2_3_1_Slot_inst_set, + Field_bitindex_Slot_inst_set, + Field_s3to1_Slot_inst_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_get_field_fn +Slot_inst16a_get_field_fns[] = { + Field_t_Slot_inst16a_get, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16a_get, + 0, + 0, + Field_r_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16a_get, + Field_st_Slot_inst16a_get, + 0, + Field_imm4_Slot_inst16a_get, + 0, + Field_i_Slot_inst16a_get, + Field_imm6lo_Slot_inst16a_get, + Field_imm6hi_Slot_inst16a_get, + Field_imm7lo_Slot_inst16a_get, + Field_imm7hi_Slot_inst16a_get, + Field_z_Slot_inst16a_get, + Field_imm6_Slot_inst16a_get, + Field_imm7_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_t2_Slot_inst16a_get, + Field_s2_Slot_inst16a_get, + Field_r2_Slot_inst16a_get, + Field_t4_Slot_inst16a_get, + Field_s4_Slot_inst16a_get, + Field_r4_Slot_inst16a_get, + Field_t8_Slot_inst16a_get, + Field_s8_Slot_inst16a_get, + Field_r8_Slot_inst16a_get, + 0, + 0, + 0, + 0, + Field_dfp_fld_r_0_Slot_inst16a_get, + Field_dfp_fld_r_2_1_Slot_inst16a_get, + Field_dfp_fld_r_3_Slot_inst16a_get, + Field_dfp_fld_r_3_1_Slot_inst16a_get, + Field_dfp_fld_s_0_Slot_inst16a_get, + Field_dfp_fld_s_3_1_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + 0, + Field_bitindex_Slot_inst16a_get, + Field_s3to1_Slot_inst16a_get, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get, + Implicit_Field_mr0_get, + Implicit_Field_mr1_get, + Implicit_Field_mr2_get, + Implicit_Field_mr3_get, + Implicit_Field_bt16_get, + Implicit_Field_bs16_get, + Implicit_Field_br16_get, + Implicit_Field_brall_get +}; + +static xtensa_set_field_fn +Slot_inst16a_set_field_fns[] = { + Field_t_Slot_inst16a_set, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16a_set, + 0, + 0, + Field_r_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16a_set, + Field_st_Slot_inst16a_set, + 0, + Field_imm4_Slot_inst16a_set, + 0, + Field_i_Slot_inst16a_set, + Field_imm6lo_Slot_inst16a_set, + Field_imm6hi_Slot_inst16a_set, + Field_imm7lo_Slot_inst16a_set, + Field_imm7hi_Slot_inst16a_set, + Field_z_Slot_inst16a_set, + Field_imm6_Slot_inst16a_set, + Field_imm7_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_t2_Slot_inst16a_set, + Field_s2_Slot_inst16a_set, + Field_r2_Slot_inst16a_set, + Field_t4_Slot_inst16a_set, + Field_s4_Slot_inst16a_set, + Field_r4_Slot_inst16a_set, + Field_t8_Slot_inst16a_set, + Field_s8_Slot_inst16a_set, + Field_r8_Slot_inst16a_set, + 0, + 0, + 0, + 0, + Field_dfp_fld_r_0_Slot_inst16a_set, + Field_dfp_fld_r_2_1_Slot_inst16a_set, + Field_dfp_fld_r_3_Slot_inst16a_set, + Field_dfp_fld_r_3_1_Slot_inst16a_set, + Field_dfp_fld_s_0_Slot_inst16a_set, + Field_dfp_fld_s_3_1_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + 0, + Field_bitindex_Slot_inst16a_set, + Field_s3to1_Slot_inst16a_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_get_field_fn +Slot_inst16b_get_field_fns[] = { + Field_t_Slot_inst16b_get, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16b_get, + 0, + 0, + Field_r_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16b_get, + Field_st_Slot_inst16b_get, + 0, + Field_imm4_Slot_inst16b_get, + 0, + Field_i_Slot_inst16b_get, + Field_imm6lo_Slot_inst16b_get, + Field_imm6hi_Slot_inst16b_get, + Field_imm7lo_Slot_inst16b_get, + Field_imm7hi_Slot_inst16b_get, + Field_z_Slot_inst16b_get, + Field_imm6_Slot_inst16b_get, + Field_imm7_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_t2_Slot_inst16b_get, + Field_s2_Slot_inst16b_get, + Field_r2_Slot_inst16b_get, + Field_t4_Slot_inst16b_get, + Field_s4_Slot_inst16b_get, + Field_r4_Slot_inst16b_get, + Field_t8_Slot_inst16b_get, + Field_s8_Slot_inst16b_get, + Field_r8_Slot_inst16b_get, + 0, + 0, + 0, + 0, + Field_dfp_fld_r_0_Slot_inst16b_get, + Field_dfp_fld_r_2_1_Slot_inst16b_get, + Field_dfp_fld_r_3_Slot_inst16b_get, + Field_dfp_fld_r_3_1_Slot_inst16b_get, + Field_dfp_fld_s_0_Slot_inst16b_get, + Field_dfp_fld_s_3_1_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + 0, + Field_bitindex_Slot_inst16b_get, + Field_s3to1_Slot_inst16b_get, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get, + Implicit_Field_mr0_get, + Implicit_Field_mr1_get, + Implicit_Field_mr2_get, + Implicit_Field_mr3_get, + Implicit_Field_bt16_get, + Implicit_Field_bs16_get, + Implicit_Field_br16_get, + Implicit_Field_brall_get +}; + +static xtensa_set_field_fn +Slot_inst16b_set_field_fns[] = { + Field_t_Slot_inst16b_set, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16b_set, + 0, + 0, + Field_r_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16b_set, + Field_st_Slot_inst16b_set, + 0, + Field_imm4_Slot_inst16b_set, + 0, + Field_i_Slot_inst16b_set, + Field_imm6lo_Slot_inst16b_set, + Field_imm6hi_Slot_inst16b_set, + Field_imm7lo_Slot_inst16b_set, + Field_imm7hi_Slot_inst16b_set, + Field_z_Slot_inst16b_set, + Field_imm6_Slot_inst16b_set, + Field_imm7_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_t2_Slot_inst16b_set, + Field_s2_Slot_inst16b_set, + Field_r2_Slot_inst16b_set, + Field_t4_Slot_inst16b_set, + Field_s4_Slot_inst16b_set, + Field_r4_Slot_inst16b_set, + Field_t8_Slot_inst16b_set, + Field_s8_Slot_inst16b_set, + Field_r8_Slot_inst16b_set, + 0, + 0, + 0, + 0, + Field_dfp_fld_r_0_Slot_inst16b_set, + Field_dfp_fld_r_2_1_Slot_inst16b_set, + Field_dfp_fld_r_3_Slot_inst16b_set, + Field_dfp_fld_r_3_1_Slot_inst16b_set, + Field_dfp_fld_s_0_Slot_inst16b_set, + Field_dfp_fld_s_3_1_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + 0, + Field_bitindex_Slot_inst16b_set, + Field_s3to1_Slot_inst16b_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_slot_internal slots[] = { + { "Inst", "x24", 0, + Slot_x24_Format_inst_0_get, Slot_x24_Format_inst_0_set, + Slot_inst_get_field_fns, Slot_inst_set_field_fns, + Slot_inst_decode, "nop" }, + { "Inst16a", "x16a", 0, + Slot_x16a_Format_inst16a_0_get, Slot_x16a_Format_inst16a_0_set, + Slot_inst16a_get_field_fns, Slot_inst16a_set_field_fns, + Slot_inst16a_decode, "" }, + { "Inst16b", "x16b", 0, + Slot_x16b_Format_inst16b_0_get, Slot_x16b_Format_inst16b_0_set, + Slot_inst16b_get_field_fns, Slot_inst16b_set_field_fns, + Slot_inst16b_decode, "nop.n" } +}; + + +/* Instruction formats. */ + +static void +Format_x24_encode (xtensa_insnbuf insn) +{ + insn[0] = 0; +} + +static void +Format_x16a_encode (xtensa_insnbuf insn) +{ + insn[0] = 0x8; +} + +static void +Format_x16b_encode (xtensa_insnbuf insn) +{ + insn[0] = 0xc; +} + +static int Format_x24_slots[] = { 0 }; + +static int Format_x16a_slots[] = { 1 }; + +static int Format_x16b_slots[] = { 2 }; + +static xtensa_format_internal formats[] = { + { "x24", 3, Format_x24_encode, 1, Format_x24_slots }, + { "x16a", 2, Format_x16a_encode, 1, Format_x16a_slots }, + { "x16b", 2, Format_x16b_encode, 1, Format_x16b_slots } +}; + + +static int +format_decoder (const xtensa_insnbuf insn) +{ + if ((insn[0] & 0x8) == 0) + return 0; /* x24 */ + if ((insn[0] & 0xc) == 0x8) + return 1; /* x16a */ + if ((insn[0] & 0xe) == 0xc) + return 2; /* x16b */ + return -1; +} + +static int length_table[256] = { + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1 +}; + +static int +length_decoder (const unsigned char *insn) +{ + int l = insn[0]; + return length_table[l]; +} + + +/* Top-level ISA structure. */ + +static xtensa_isa_internal xtensa_modules = { + 0 /* little-endian */, + 3 /* insn_size */, 0, + 3, formats, format_decoder, length_decoder, + 3, slots, + 83 /* num_fields */, + 140, operands, + 390, iclasses, + 513, opcodes, 0, + 8, regfiles, + NUM_STATES, states, 0, + NUM_SYSREGS, sysregs, 0, + { MAX_SPECIAL_REG, MAX_USER_REG }, { 0, 0 }, + 6, interfaces, 0, + 0, funcUnits, 0 +}; diff --git a/target/xtensa/cores.list b/target/xtensa/cores.list index a526a71cfd98..a936b26914c8 100644 --- a/target/xtensa/cores.list +++ b/target/xtensa/cores.list @@ -8,3 +8,4 @@ core-lx106.c core-sample_controller.c core-test_kc705_be.c core-test_mmuhifi_c3.c +core-esp32.c diff --git a/target/xtensa/gdbstub.c b/target/xtensa/gdbstub.c index 4b3bfb7e59c4..91e1465ade26 100644 --- a/target/xtensa/gdbstub.c +++ b/target/xtensa/gdbstub.c @@ -46,10 +46,17 @@ void xtensa_count_regs(const XtensaConfig *config, unsigned i; bool count_core_regs = true; + /* Espressif local: allow changing the behavior here based on QEMU_XTENSA_COUNT_WINDOW_REGS + * environment variable. + */ + const char* count_window_regs_env = getenv("QEMU_XTENSA_COUNT_WINDOW_REGS"); + bool count_window_regs = count_window_regs_env != NULL && strcmp(count_window_regs_env, "0") != 0; + for (i = 0; config->gdb_regmap.reg[i].targno >= 0; ++i) { if (config->gdb_regmap.reg[i].type != xtRegisterTypeTieState && config->gdb_regmap.reg[i].type != xtRegisterTypeMapped && - config->gdb_regmap.reg[i].type != xtRegisterTypeUnmapped) { + config->gdb_regmap.reg[i].type != xtRegisterTypeUnmapped && + (config->gdb_regmap.reg[i].type != xtRegisterTypeWindow || count_window_regs)) { ++*n_regs; if (count_core_regs) { if ((config->gdb_regmap.reg[i].flags & diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c index dbeb97a953cc..57de5eac3777 100644 --- a/target/xtensa/helper.c +++ b/target/xtensa/helper.c @@ -185,6 +185,15 @@ static void xtensa_core_class_init(ObjectClass *oc, void *data) * in the gdb/xtensa-config.c inside gdb source tree or inside gdb overlay. */ cc->gdb_num_core_regs = config->gdb_regmap.num_regs; + + /* Espressif local: allow changing the behavior here using + * QEMU_XTENSA_CORE_REGS_ONLY environment variable, to support different + * GDB builds + */ + const char* core_regs_only = getenv("QEMU_XTENSA_CORE_REGS_ONLY"); + if (core_regs_only != NULL && strcmp(core_regs_only, "0") != 0) { + cc->gdb_num_core_regs = config->gdb_regmap.num_core_regs; + } } void xtensa_register_core(XtensaConfigList *node) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 0cf3075649d1..0c5c080cf044 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -2671,6 +2671,12 @@ static void translate_wur(DisasContext *dc, const OpcodeArg arg[], tcg_gen_mov_i32(cpu_UR[par[0]], arg[0].in); } +static void translate_xur_f64(DisasContext *dc, const OpcodeArg arg[], + const uint32_t par[]) +{ + /* no-op */ +} + static void translate_xor(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { @@ -5445,6 +5451,24 @@ static const XtensaOpcodeOps core_ops[] = { .name = "wur.expstate", .translate = translate_wur, .par = (const uint32_t[]){EXPSTATE}, + }, { + .name = "wur.f64r_lo", + .translate = translate_xur_f64, + }, { + .name = "wur.f64r_hi", + .translate = translate_xur_f64, + }, { + .name = "wur.f64s", + .translate = translate_xur_f64, + }, { + .name = "rur.f64r_lo", + .translate = translate_xur_f64, + }, { + .name = "rur.f64r_hi", + .translate = translate_xur_f64, + }, { + .name = "rur.f64s", + .translate = translate_xur_f64, }, { .name = "wur.threadptr", .translate = translate_wur,