Repository: compiler-explorer/compiler-explorer
Pull request #7368 (2025-02-06 02:08:17)

Add support for ORCA/C
[ORCA/C](https://github.com/byteworksinc/ORCA-C) is a C compiler that natively runs on and targets the Apple IIGS. ORCA/C and the programs it generates can be run on modern Linux systems by using an emulation tool called [Golden Gate](https://goldengate.gitlab.io).

This adds support for ORCA/C (run via Golden Gate) in Compiler Explorer. It uses its own assembly format and objdumper (provided by Golden Gate), so support for those is added. An extra configuration option was also added to support execution via an emulator, bypassing the usual check that executables can run natively. Asm docs for the WDC 65C816 processor were also added.

ORCA/C and Golden Gate are not Free Software, but their rights holders have given permission for them to be used on Compiler Explorer. Tarballs for them can be supplied privately. See infra PR: compiler-explorer/infra#1521

mattgodbolt: The change seems to work. There are some regexes that need a quick look.

Also @sheumann do we need to pop up a license/link when the user selects one of these compilers
mattgodbolt: Also mentioned in the other thread but I checked on our production systems and, as expected:
```
^[[A^[[A^[[A^[[A^[[A^[[A^[[A^[[A^[[A^[[A2025-02-12 19:59:35,698 lib.installable.archives INFO     Piping to tar zxf - --strip-components 1
^[[A^[[A^[[A^[[A^[[A^[[A^[[A^[[A^[[A^[[A2025-02-12 19:59:35,911 lib.installation_context INFO     Moving from staging (/opt/compiler-explorer/staging/b3be4775-6513-4b02-a3e2-9fcbc95a977d/goldengate-2.0.9) to final destination (/opt/compiler-explorer/goldengate-2.0.9)
2025-02-12 19:59:35,943 lib.installation_context INFO     Destination /opt/compiler-explorer/goldengate-2.0.9 exists, temporarily moving out of the way (to /opt/compiler-explorer/staging/b3be4775-6513-4b02-a3e2-9fcbc95a977d.orig)
2025-02-12 19:59:35,959 lib.installation_context INFO     Removing temporarily moved /opt/compiler-explorer/staging/b3be4775-6513-4b02-a3e2-9fcbc95a977d.orig
2025-02-12 19:59:36,111 lib.installable.archives INFO     Piping to tar zxf - --xattrs --strip-components 1
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Languages/cc': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Languages/linker': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/ace.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/adb.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/appleshare.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/assert.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/control.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/ctype.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/desk.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/dialog.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/errno.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/event.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/fcntl.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/fenv.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/finder.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/float.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/font.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/gsbug.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/gsos.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/hyperstudio.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/hyperxcmd.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/intmath.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/inttypes.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/iso646.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/limits.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/lineedit.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/list.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/loader.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/locale.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/locator.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/math.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/mediacontrol.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/memory.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/menu.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/midi.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/midisynth.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/misctool.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/noteseq.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/notesyn.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/orca.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/print.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/prodos.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/qdaux.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/quickdraw.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/resources.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/sane.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/scheduler.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/scrap.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/setjmp.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/shell.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/signal.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/sound.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/Speech.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/stdalign.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/stdarg.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/stdbool.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/stddef.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/stdfile.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/stdint.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/stdio.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/stdlib.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/stdnoreturn.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/string.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/textedit.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/texttool.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/tgmath.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/time.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/toollib.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/types.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/uchar.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/video.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCACDefs/window.h': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/ORCALib': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/SysFloat': Operation not supported
tar: setxattrat: Cannot set 'user.com.apple.FinderInfo' extended attribute for file 'Libraries/SysLib': Operation not supported
2025-02-12 19:59:38,158 lib.installation_context INFO     Moving from staging (/opt/compiler-explorer/staging/339abb71-b1a4-4fd6-8ac7-024c6a73ea30/orca-c-2.2.1) to final destination (/opt/compiler-explorer/orca-c-2.2.1)
2025-02-12 19:59:38,499 lib.installation_context INFO     Destination /opt/compiler-explorer/orca-c-2.2.1 exists but is empty; deleting it
2025-02-12 19:59:38,530 lib.ce_install  INFO     compilers/c/orca-c 2.2.1 installed OK
3 packages installed OK, 0 skipped, and 0 failed installation
Feb/12 19:59 admin-node~/infra (main|✔) 24.1s $ 
```

This might prevent this from being useful.

Patch:
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index eafdadd86..db8e13501 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -153,3 +153,4 @@ From oldest to newest contributor, we would like to thank:
 - [James Touton](https://github.com/Bekenn)
 - [Waqar Ahmed](https://github.com/waqar144)
 - [Niles Salter](https://github.com/Validark)
+- [Stephen Heumann](https://github.com/sheumann)
diff --git a/docs/AddingACompiler.md b/docs/AddingACompiler.md
index d604fcb18..661bb049a 100644
--- a/docs/AddingACompiler.md
+++ b/docs/AddingACompiler.md
@@ -99,6 +99,7 @@ once the site runs on the Amazon environment, the `&clang` group **will not** ha
 | versionRe            | RegExp     | A regular expression used to capture the version from the version output                                                                                           |
 | compilerType         | String     | The name of the class handling this compiler                                                                                                                       |
 | interpreted          | Boolean    | Whether this is an interpreted language, and so the "compiler" is really an interpreter                                                                            |
+| emulated             | Boolean    | Whether the compiler's output is run via an emulator (specified by `executionWrapper`) rather than natively                                                        |
 | executionWrapper     | Path       | Path to script that can execute the compiler's output (e.g. could run under `qemu` or `mpi_run` or similar)                                                        |
 | executionWrapperArgs | String     | List of arguments passed to the execution wrapper (separated by `\|` character)                                                                                    |
 | demangler            | String     | Path to the demangler tool                                                                                                                                         |
diff --git a/etc/config/c.amazon.properties b/etc/config/c.amazon.properties
index 06149ba66..c0b978af6 100644
--- a/etc/config/c.amazon.properties
+++ b/etc/config/c.amazon.properties
@@ -1,4 +1,4 @@
-compilers=&cgcc86:&cclang:&nvc_x86:&armcclang32:&armcclang64:&cmosclang-trunk:&rvcclang:&wasmcclang:&ppci:&cicc:&cicx:&ccl:&ccross:&cgcc-classic:&cc65:&sdcc:&ctendra:&tinycc:&zigcc:&cproc86:&chibicc:&z88dk:&compcert:godbolt.org@443/winprod:&movfuscator:&lc3:&upmem-clang:&cvast
+compilers=&cgcc86:&cclang:&nvc_x86:&armcclang32:&armcclang64:&cmosclang-trunk:&rvcclang:&wasmcclang:&ppci:&cicc:&cicx:&ccl:&ccross:&cgcc-classic:&cc65:&sdcc:&ctendra:&tinycc:&zigcc:&cproc86:&chibicc:&z88dk:&compcert:godbolt.org@443/winprod:&movfuscator:&lc3:&upmem-clang:&cvast:&orcac
 defaultCompiler=cg142
 # We use the llvm-trunk demangler for all c/c++ compilers, as c++filt tends to lag behind 
 demangler=/opt/compiler-explorer/clang-trunk/bin/llvm-cxxfilt
@@ -3515,6 +3515,31 @@ compiler.cvast-trunk.exe=/opt/compiler-explorer/vast-trunk/bin/vast-front
 compiler.cvast-trunk.isNightly=true
 compiler.cvast-trunk.options=-resource-dir /opt/compiler-explorer/clang-17.0.1/lib/clang/17/ --gcc-toolchain=/opt/compiler-explorer/gcc-13.2.0
 
+################################
+# ORCA/C (run via Golden Gate emulator)
+group.orcac.groupName=ORCA/C
+group.orcac.compilers=orcac221:orcac220:orcac210
+group.orcac.isSemVer=true
+group.orcac.baseName=ORCA/C
+group.orcac.executionWrapper=/opt/compiler-explorer/goldengate-2.0.9/bin/iix
+group.orcac.compilerType=orca
+group.orcac.objdumper=/opt/compiler-explorer/goldengate-2.0.9/bin/dumpobj
+group.orcac.objdumperType=goldengate
+group.orcac.emulated=true
+group.orcac.instructionSet=wdc65c816
+group.orcac.includeFlag=cc=-I
+group.orcac.versionFlag=compile|dummy.c
+group.orcac.exe=/opt/compiler-explorer/goldengate-2.0.9/bin/iix
+# Disable check for same compiler exe, because these are all run using the
+# same emulator.
+# Disabled: orcac210 orcac220 orcac221
+compiler.orcac210.goldenGate=/opt/compiler-explorer/orca-c-2.1.0
+compiler.orcac210.semver=2.1.0
+compiler.orcac220.goldenGate=/opt/compiler-explorer/orca-c-2.2.0
+compiler.orcac220.semver=2.2.0
+compiler.orcac221.goldenGate=/opt/compiler-explorer/orca-c-2.2.1
+compiler.orcac221.semver=2.2.1
+
 #################################
 #################################
 # Libraries
diff --git a/etc/config/execution.amazonwin.properties b/etc/config/execution.amazonwin.properties
index cfb6cc2ed..e498da3c2 100644
--- a/etc/config/execution.amazonwin.properties
+++ b/etc/config/execution.amazonwin.properties
@@ -1,3 +1,4 @@
 sandboxType=cewrapper
 executionType=cewrapper
 cewrapper=C:/cewrapper/cewrapper.exe
+unbufferStdoutExe=
diff --git a/etc/config/execution.defaults.properties b/etc/config/execution.defaults.properties
index 6352ef5f6..4e4261715 100644
--- a/etc/config/execution.defaults.properties
+++ b/etc/config/execution.defaults.properties
@@ -14,3 +14,8 @@ firejail.profile.wine=etc/firejail/wine.profile
 cewrapper=
 cewrapper.config.sandbox=etc/cewrapper/user-execution.json
 cewrapper.config.execute=etc/cewrapper/compilers-and-tools.json
+
+# Prefix execution with `stdbuf -o0` to have stdout output also for crashing executions.
+# Discussed further in https://github.com/compiler-explorer/compiler-explorer/issues/7239
+unbufferStdoutExe=stdbuf
+unbufferStdoutArgs=-o0
diff --git a/etc/config/sponsors.yaml b/etc/config/sponsors.yaml
index 678c58743..8c7a55429 100644
--- a/etc/config/sponsors.yaml
+++ b/etc/config/sponsors.yaml
@@ -517,3 +517,5 @@ levels:
       - woobwoobwoob
       - Drew Dormann
       - Ryan Lee
+      - elliot
+      - Cemalettin Dervis
diff --git a/etc/scripts/docenizers/Makefile b/etc/scripts/docenizers/Makefile
index 6ae8d0bf3..735af4759 100644
--- a/etc/scripts/docenizers/Makefile
+++ b/etc/scripts/docenizers/Makefile
@@ -1,6 +1,7 @@
 GEN_DIR := ../../../lib/asm-docs/generated
 all: \
  $(GEN_DIR)/asm-docs-6502.ts \
+ $(GEN_DIR)/asm-docs-65c816.ts \
  $(GEN_DIR)/asm-docs-amd64.ts \
  $(GEN_DIR)/asm-docs-arm32.ts \
  $(GEN_DIR)/asm-docs-aarch64.ts \
@@ -14,7 +15,9 @@ all: \
  $(GEN_DIR)/asm-docs-python.ts
 
 $(GEN_DIR)/asm-docs-6502.ts: docenizer-6502.py
-	python3 $<
+	python3 $< -o $@ -c 6502 -m 65c02
+$(GEN_DIR)/asm-docs-65c816.ts: docenizer-6502.py
+	python3 $< -o $@ -c 65c816 -m 65c816
 $(GEN_DIR)/asm-docs-amd64.ts: docenizer-amd64.py
 	python3 $< -o $@
 $(GEN_DIR)/asm-docs-arm32.ts: docenizer-arm.py arm32.json
@@ -36,4 +39,4 @@ $(GEN_DIR)/asm-docs-sass.ts: docenizer-ptx-sass.py
 $(GEN_DIR)/asm-docs-python.ts: docenizer-python.py
 	python3 $< -o $@
 $(GEN_DIR)/asm-docs-riscv64.ts: docenizer-riscv64.py
-	python3 $< -o $@
\ No newline at end of file
+	python3 $< -o $@
diff --git a/etc/scripts/docenizers/docenizer-6502.py b/etc/scripts/docenizers/docenizer-6502.py
index a038f535e..a8182fa07 100755
--- a/etc/scripts/docenizers/docenizer-6502.py
+++ b/etc/scripts/docenizers/docenizer-6502.py
@@ -6,11 +6,19 @@ import os.path
 import re
 import urllib.request
 
-
-DOC_URL_BASE = "https://raw.githubusercontent.com/mist64/c64ref/4274bd8782c5d3b18c68e6b9479b0ec751eb96b1/Source/6502/"
+parser = argparse.ArgumentParser(description='Docenizes 6502 family CPU documentation')
+parser.add_argument('-o', '--outputpath', type=str, help='Final path of the .ts file. Default is ./asm-docs-6502.ts',
+                    default='./asm-docs-6502.ts')
+parser.add_argument('-c', '--cpu', type=str, help='CPU to generate documentation for. Default is 6502',
+                    default="6502")
+parser.add_argument('-m', '--maxcpu', type=str, help='Maximum CPU to include in documentation. Default is 65c02',
+                    default="65c02")
+
+DOC_URL_BASE = "https://raw.githubusercontent.com/mist64/c64ref/f5792f46cfa9e05d006e5dd4f24199fed9091100/src/6502/"
 doc_files = {f"{DOC_URL_BASE}{filename}":cpu_type for filename, cpu_type in {
     "cpu_6502.txt" : "6502",
     "cpu_65c02.txt" : "65c02",
+    "cpu_65c816.txt" : "65c816",
     }.items()
 }
 mode_change_regex = re.compile(r"\[(?P<mode_name>.*)\]")
@@ -33,9 +41,10 @@ class Instruction:
         self.name = ""
         self.long_name = ""
         self.description = []
+        self.undocumented = False
 
     def html_description(self):
-        if self.description:
+        if self.description and self.cpu_type != "65c816":
             return "".join(
                 f"<p>{escape_quotes(desc_line)}</p>"
                 for desc_line in self.description
@@ -48,11 +57,16 @@ class Instruction:
             return f"<p>{self.mnemonic}</p>"
 
 
-def get_instructions():
+def get_instructions(cpu, maxcpu):
     """Gathers all instruction data and returns it in a dictionary."""
     instructions = {}
+    extra_cpu = False
     for f, t in doc_files.items():
-        instructions_from_file(f, t, instructions)
+        instructions_from_file(f, cpu if not extra_cpu else t, instructions)
+        if t == maxcpu:
+            break
+        if t == cpu:
+            extra_cpu = True
     return instructions
 
 
@@ -70,7 +84,7 @@ def instructions_from_file(filename, cpu_type, instructions):
                 continue
             regex_match = mode_change_regex.match(line)
             if regex_match:
-                parse_mode = mode_change(regex_match.group("mode_name"))
+                parse_mode = mode_change(regex_match.group("mode_name"), cpu_type)
                 continue
             if parse_mode == ParseMode.IGNORE:
                 continue
@@ -96,7 +110,7 @@ def remove_comments(line):
         return line
 
 
-def mode_change(mode_name):
+def mode_change(mode_name, cpu_type):
     if mode_name == "mnemos":
         return ParseMode.MNEMONICS
     elif mode_name == "documentation-mnemos":
@@ -132,6 +146,8 @@ def parse_descriptions(line, line_num, cpu_type, instructions):
         mnemonic = parse_descriptions.last_mnemonic
         description = continue_match.group("description")
         instructions[mnemonic].description.append(description)
+        if re.search("undocumented", description):
+            instructions[mnemonic].undocumented = True
 
 
 def write_script(filename, instructions):
@@ -141,6 +157,8 @@ def write_script(filename, instructions):
               "    if (!opcode) return;",
               "    switch (opcode.toUpperCase()) {"]
     for inst in instructions.values():
+        if inst.undocumented and inst.cpu_type != "6502":
+            continue
         script.append(f"        case \"{inst.mnemonic}\":")
         script.append("            return {")
         html = f"{16 * ' '}\"html\": \""
@@ -155,7 +173,6 @@ def write_script(filename, instructions):
             script.append(f"{16 * ' '}\"tooltip\": \"{safe_n}\",")
         else:
             script.append(f"{16 * ' '}\"tooltip\": \"{inst.mnemonic}\",")
-        # Will need to be replaced when other 65xx CPUs are added
         s = "https://www.pagetable.com/c64ref/6502/?cpu="
         e = "&tab=2#"
         t = inst.cpu_type
@@ -175,23 +192,12 @@ def escape_quotes(string):
     return string.replace("\"", "\\\"")
 
 
-def get_arguments():
-    parser = argparse.ArgumentParser()
-    help_text = "the location to which the script will be written"
-    relative_path = "../../../../lib/asm-docs/generated/asm-docs-6502.ts"
-    script_path = os.path.realpath(__file__)
-    script_dir = os.path.dirname(script_path)
-    default_path = os.path.normpath(script_dir + relative_path)
-    parser.add_argument("-o", "--output", help=help_text, default=default_path)
-    return parser.parse_args()
-
-
 def main():
-    args = get_arguments()
-    instructions = get_instructions()
+    args = parser.parse_args()
+    instructions = get_instructions(args.cpu, args.maxcpu)
     #for inst in instructions.values():
         #print(inst.__dict__)
-    write_script(args.output, instructions)
+    write_script(args.outputpath, instructions)
 
 
 if __name__ == "__main__":
diff --git a/lib/asm-docs/_all.ts b/lib/asm-docs/_all.ts
index 4197f0409..7ba601de4 100644
--- a/lib/asm-docs/_all.ts
+++ b/lib/asm-docs/_all.ts
@@ -34,3 +34,4 @@ export {PowerDocumentationProvider} from './power.js';
 export {PythonDocumentationProvider} from './python.js';
 export {Riscv64DocumentationProvider} from './riscv64.js';
 export {SASSDocumentationProvider} from './sass.js';
+export {WDC65c816DocumentationProvider} from './wdc65c816.js';
diff --git a/lib/asm-docs/generated/asm-docs-6502.ts b/lib/asm-docs/generated/asm-docs-6502.ts
index 18a106c6c..0775e999b 100644
--- a/lib/asm-docs/generated/asm-docs-6502.ts
+++ b/lib/asm-docs/generated/asm-docs-6502.ts
@@ -19,7 +19,7 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "ASL":
             return {
-                "html": "<p>The shift left instruction shifts either the accumulator or the address memory location 1 bit to the left, with the bit 0 always being set to 0 and the the input bit 7 being stored in the carry flag. ASL either shifts the accumulator left 1 bit or is a read/modify/write instruction that affects only memory.</p><p>The instruction does not affect the overflow bit, sets N equal to the result bit 7 (bit 6 in the input), sets Z flag if the result is equal to 0, otherwise resets Z and stores the input bit 7 in the carry flag.</p>",
+                "html": "<p>The shift left instruction shifts either the accumulator or the address memory location 1 bit to the left, with the bit 0 always being set to 0 and the input bit 7 being stored in the carry flag. ASL either shifts the accumulator left 1 bit or is a read/modify/write instruction that affects only memory.</p><p>The instruction does not affect the overflow bit, sets N equal to the result bit 7 (bit 6 in the input), sets Z flag if the result is equal to 0, otherwise resets Z and stores the input bit 7 in the carry flag.</p>",
                 "tooltip": "Arithmetic Shift Left",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#ASL",
             };
@@ -40,7 +40,7 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "BEQ":
             return {
-                "html": "<p>This instruction could also be called \"Branch on Equal.\"</p><p>It takes a conditional branch whenever the Z flag is on or the previ ous result is equal to 0.</p><p>BEQ does not affect any of the flags or registers other than the program counter and only then when the Z flag is set.</p>",
+                "html": "<p>This instruction could also be called \"Branch on Equal.\"</p><p>It takes a conditional branch whenever the Z flag is on or the previous result is equal to 0.</p><p>BEQ does not affect any of the flags or registers other than the program counter and only then when the Z flag is set.</p>",
                 "tooltip": "Branch on Result Zero",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#BEQ",
             };
@@ -75,7 +75,7 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "BRK":
             return {
-                "html": "<p>The break command causes the microprocessor to go through an inter rupt sequence under program control. This means that the program counter of the second byte after the BRK. is automatically stored on the stack along with the processor status at the beginning of the break instruction. The microprocessor then transfers control to the interrupt vector.</p><p>Other than changing the program counter, the break instruction changes no values in either the registers or the flags.</p>",
+                "html": "<p>The break command causes the microprocessor to go through an interrupt sequence under program control. This means that the program counter of the second byte after the BRK. is automatically stored on the stack along with the processor status at the beginning of the break instruction. The microprocessor then transfers control to the interrupt vector.</p><p>Other than changing the program counter, the break instruction changes no values in either the registers or the flags.</p>",
                 "tooltip": "Break Command",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#BRK",
             };
@@ -96,7 +96,7 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "CLC":
             return {
-                "html": "<p>This instruction initializes the carry flag to a 0. This op eration should normally precede an ADC loop. It is also useful when used with a R0L instruction to clear a bit in memory.</p><p>This instruction affects no registers in the microprocessor and no flags other than the carry flag which is reset.</p>",
+                "html": "<p>This instruction initializes the carry flag to a 0. This operation should normally precede an ADC loop. It is also useful when used with a R0L instruction to clear a bit in memory.</p><p>This instruction affects no registers in the microprocessor and no flags other than the carry flag which is reset.</p>",
                 "tooltip": "Clear Carry Flag",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#CLC",
             };
@@ -117,7 +117,7 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "CLV":
             return {
-                "html": "<p>This instruction clears the overflow flag to a 0. This com mand is used in conjunction with the set overflow pin which can change the state of the overflow flag with an external signal.</p><p>CLV affects no registers in the microprocessor and no flags other than the overflow flag which is set to a 0.</p>",
+                "html": "<p>This instruction clears the overflow flag to a 0. This command is used in conjunction with the set overflow pin which can change the state of the overflow flag with an external signal.</p><p>CLV affects no registers in the microprocessor and no flags other than the overflow flag which is set to a 0.</p>",
                 "tooltip": "Clear Overflow Flag",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#CLV",
             };
@@ -138,7 +138,7 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "CPY":
             return {
-                "html": "<p>This instruction performs a two's complement subtraction between the index register Y and the specified memory location. The results of the subtraction are not stored anywhere. The instruction is strictly used to set the flags.</p><p>CPY affects no registers in the microprocessor and also does not affect the overflow flag. If the value in the index register Y is equal to or greater than the value in the memory, the carry flag will be set, otherwise it will be cleared. If the results of the subtract- tion contain bit 7 on the N bit will be set, otherwise it will be cleared. If the value in the index register Y and the value in the memory are equal, the zero flag will be set, otherwise it will be cleared.</p>",
+                "html": "<p>This instruction performs a two's complement subtraction between the index register Y and the specified memory location. The results of the subtraction are not stored anywhere. The instruction is strictly used to set the flags.</p><p>CPY affects no registers in the microprocessor and also does not affect the overflow flag. If the value in the index register Y is equal to or greater than the value in the memory, the carry flag will be set, otherwise it will be cleared. If the results of the subtraction contain bit 7 on the N bit will be set, otherwise it will be cleared. If the value in the index register Y and the value in the memory are equal, the zero flag will be set, otherwise it will be cleared.</p>",
                 "tooltip": "Compare Index Register Y To Memory",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#CPY",
             };
@@ -159,7 +159,7 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "DEY":
             return {
-                "html": "<p>This instruction subtracts one from the current value in the in dex register Y and stores the result into the index register Y. The result does not affect or consider carry so that the value in the index register Y is decremented to 0 and then through 0 to FF.</p><p>Decrement Y does not affect the carry or overflow flags; if the Y register contains bit 7 on as a result of the decrement the N flag is set, otherwise the N flag is reset. If the Y register is 0 as a result of the decrement, the Z flag is set otherwise the Z flag is reset. This instruction only affects the index register Y.</p>",
+                "html": "<p>This instruction subtracts one from the current value in the index register Y and stores the result into the index register Y. The result does not affect or consider carry so that the value in the index register Y is decremented to 0 and then through 0 to FF.</p><p>Decrement Y does not affect the carry or overflow flags; if the Y register contains bit 7 on as a result of the decrement the N flag is set, otherwise the N flag is reset. If the Y register is 0 as a result of the decrement, the Z flag is set otherwise the Z flag is reset. This instruction only affects the index register Y.</p>",
                 "tooltip": "Decrement Index Register Y By One",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#DEY",
             };
@@ -194,14 +194,14 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "JMP":
             return {
-                "html": "<p>In this instruction, the data from the memory location located in the program sequence after the OP CODE is loaded into the low order byte of the program counter (PCL) and the data from the next memory location after that is loaded into the high order byte of the program counter (PCH).</p><p>This instruction establishes a new valne for the program counter.</p><p>It affects only the program counter in the microprocessor and affects no flags in the status register.</p>",
+                "html": "<p>In this instruction, the data from the memory location located in the program sequence after the OP CODE is loaded into the low order byte of the program counter (PCL) and the data from the next memory location after that is loaded into the high order byte of the program counter (PCH).</p><p>This instruction establishes a new value for the program counter.</p><p>It affects only the program counter in the microprocessor and affects no flags in the status register.</p>",
                 "tooltip": "JMP Indirect",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#JMP",
             };
 
         case "JSR":
             return {
-                "html": "<p>This instruction transfers control of the program counter to a subroutine location but leaves a return pointer on the stack to allow the user to return to perform the next instruction in the main program after the subroutine is complete. To accomplish this, JSR instruction stores the program counter address which points to the last byte of the jump instruc tion onto the stack using the stack pointer. The stack byte contains the program count high first, followed by program count low. The JSR then transfers the addresses following the jump instruction to the program counter low and the program counter high, thereby directing the program to begin at that new address.</p><p>The JSR instruction affects no flags, causes the stack pointer to be decremented by 2 and substitutes new values into the program counter low and the program counter high.</p>",
+                "html": "<p>This instruction transfers control of the program counter to a subroutine location but leaves a return pointer on the stack to allow the user to return to perform the next instruction in the main program after the subroutine is complete. To accomplish this, JSR instruction stores the program counter address which points to the last byte of the jump instruction onto the stack using the stack pointer. The stack byte contains the program count high first, followed by program count low. The JSR then transfers the addresses following the jump instruction to the program counter low and the program counter high, thereby directing the program to begin at that new address.</p><p>The JSR instruction affects no flags, causes the stack pointer to be decremented by 2 and substitutes new values into the program counter low and the program counter high.</p>",
                 "tooltip": "Jump To Subroutine",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#JSR",
             };
@@ -257,7 +257,7 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "PHP":
             return {
-                "html": "<p>This instruction transfers the contents of the processor status reg ister unchanged to the stack, as governed by the stack pointer.</p><p>The PHP instruction affects no registers or flags in the microprocessor.</p>",
+                "html": "<p>This instruction transfers the contents of the processor status register unchanged to the stack, as governed by the stack pointer.</p><p>The PHP instruction affects no registers or flags in the microprocessor.</p>",
                 "tooltip": "Push Processor Status On Stack",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#PHP",
             };
@@ -271,28 +271,28 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "PLP":
             return {
-                "html": "<p>This instruction transfers the next value on the stack to the Proces sor Status register, thereby changing all of the flags and setting the mode switches to the values from the stack.</p><p>The PLP instruction affects no registers in the processor other than the status register. This instruction could affect all flags in the status register.</p>",
+                "html": "<p>This instruction transfers the next value on the stack to the Processor Status register, thereby changing all of the flags and setting the mode switches to the values from the stack.</p><p>The PLP instruction affects no registers in the processor other than the status register. This instruction could affect all flags in the status register.</p>",
                 "tooltip": "Pull Processor Status From Stack",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#PLP",
             };
 
         case "ROL":
             return {
-                "html": "<p>The rotate left instruction shifts either the accumulator or addressed memory left 1 bit, with the input carry being stored in bit 0 and with the input bit 7 being stored in the carry flags.</p><p>The ROL instruction either shifts the accumulator left 1 bit and stores the carry in accumulator bit 0 or does not affect the internal registers at all. The ROL instruction sets carry equal to the input bit 7, sets N equal to the input bit 6 , sets the Z flag if the result of the ro tate is 0, otherwise it resets Z and does not affect the overflow flag at all.</p>",
+                "html": "<p>The rotate left instruction shifts either the accumulator or addressed memory left 1 bit, with the input carry being stored in bit 0 and with the input bit 7 being stored in the carry flags.</p><p>The ROL instruction either shifts the accumulator left 1 bit and stores the carry in accumulator bit 0 or does not affect the internal registers at all. The ROL instruction sets carry equal to the input bit 7, sets N equal to the input bit 6 , sets the Z flag if the result of the rotate is 0, otherwise it resets Z and does not affect the overflow flag at all.</p>",
                 "tooltip": "Rotate Left",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#ROL",
             };
 
         case "ROR":
             return {
-                "html": "<p>The rotate right instruction shifts either the accumulator or addressed memory right 1 bit with bit 0 shifted into the carry and carry shifted into bit 7.</p><p>The ROR instruction either shifts the accumulator right 1 bit and stores the carry in accumulator bit 7 or does not affect the internal regis ters at all. The ROR instruction sets carry equal to input bit 0, sets N equal to the input carry and sets the Z flag if the result of the rotate is 0; otherwise it resets Z and does not affect the overflow flag at all.</p><p>(Available on Microprocessors after June, 1976)</p>",
+                "html": "<p>The rotate right instruction shifts either the accumulator or addressed memory right 1 bit with bit 0 shifted into the carry and carry shifted into bit 7.</p><p>The ROR instruction either shifts the accumulator right 1 bit and stores the carry in accumulator bit 7 or does not affect the internal registers at all. The ROR instruction sets carry equal to input bit 0, sets N equal to the input carry and sets the Z flag if the result of the rotate is 0; otherwise it resets Z and does not affect the overflow flag at all.</p><p>(Available on Microprocessors after June, 1976)</p>",
                 "tooltip": "Rotate Right",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#ROR",
             };
 
         case "RTI":
             return {
-                "html": "<p>This instruction transfers from the stack into the microprocessor the processor status and the program counter location for the instruction which was interrupted. By virtue of the interrupt having stored this data before executing the instruction and thei fact that the RTI reinitializes the microprocessor to the same state as when it was interrupted, the combination of interrupt plus RTI allows truly reentrant coding.</p><p>The RTI instruction reinitializes all flags to the position to the point they were at the time the interrupt was taken and sets the program counter back to its pre-interrupt state. It affects no other registers in the microprocessor.</p>",
+                "html": "<p>This instruction transfers from the stack into the microprocessor the processor status and the program counter location for the instruction which was interrupted. By virtue of the interrupt having stored this data before executing the instruction and the fact that the RTI reinitializes the microprocessor to the same state as when it was interrupted, the combination of interrupt plus RTI allows truly reentrant coding.</p><p>The RTI instruction reinitializes all flags to the position to the point they were at the time the interrupt was taken and sets the program counter back to its pre-interrupt state. It affects no other registers in the microprocessor.</p>",
                 "tooltip": "Return From Interrupt",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#RTI",
             };
@@ -300,7 +300,7 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
         case "RTS":
             return {
                 "html": "<p>This instruction loads the program count low and program count high from the stack into the program counter and increments the program counter so that it points to the instruction following the JSR. The stack pointer is adjusted by incrementing it twice.</p><p>The RTS instruction does not affect any flags and affects only PCL and PCH.</p>",
-                "tooltip": "Return From Subroutme",
+                "tooltip": "Return From Subroutine",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#RTS",
             };
 
@@ -313,7 +313,7 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "SEC":
             return {
-                "html": "<p>This instruction initializes the carry flag to a 1. This op eration should normally precede a SBC loop. It is also useful when used with a ROL instruction to initialize a bit in memory to a 1.</p><p>This instruction affects no registers in the microprocessor and no flags other than the carry flag which is set.</p>",
+                "html": "<p>This instruction initializes the carry flag to a 1. This operation should normally precede a SBC loop. It is also useful when used with a ROL instruction to initialize a bit in memory to a 1.</p><p>This instruction affects no registers in the microprocessor and no flags other than the carry flag which is set.</p>",
                 "tooltip": "Set Carry Flag",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#SEC",
             };
@@ -355,7 +355,7 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "TAX":
             return {
-                "html": "<p>This instruction takes the value from accumulator A and trans fers or loads it into the index register X without disturbing the content of the accumulator A.</p><p>TAX only affects the index register X, does not affect the carry or overflow flags. The N flag is set if the resultant value in the index register X has bit 7 on, otherwise N is reset. The Z bit is set if the content of the register X is 0 as aresult of theopera tion, otherwise it is reset.</p>",
+                "html": "<p>This instruction takes the value from accumulator A and trans fers or loads it into the index register X without disturbing the content of the accumulator A.</p><p>TAX only affects the index register X, does not affect the carry or overflow flags. The N flag is set if the resultant value in the index register X has bit 7 on, otherwise N is reset. The Z bit is set if the content of the register X is 0 as a result of the operation, otherwise it is reset.</p>",
                 "tooltip": "Transfer Accumulator To Index X",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#TAX",
             };
@@ -363,7 +363,7 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
         case "TAY":
             return {
                 "html": "<p>This instruction moves the value of the accumulator into index register Y without affecting the accumulator.</p><p>TAY instruction only affects the Y register and does not affect either the carry or overflow flags. If the index register Y has bit 7 on, then N is set, otherwise it is reset. If the content of the index register Y equals 0 as a result of the operation, Z is set on, otherwise it is reset.</p>",
-                "tooltip": "Transfer Accumula Tor To Index Y",
+                "tooltip": "Transfer Accumulator To Index Y",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#TAY",
             };
 
@@ -390,7 +390,7 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "TYA":
             return {
-                "html": "<p>This instruction moves the value that is in the index register Y to accumulator A without disturbing the content of the register Y.</p><p>TYA does not affect any other register other than the accumula tor and does not affect the carry or overflow flag. If the result in the accumulator A has bit 7 on, the N flag is set, otherwise it is reset. If the resultant value in the accumulator A is 0, then the Z flag is set, otherwise it is reset.</p>",
+                "html": "<p>This instruction moves the value that is in the index register Y to accumulator A without disturbing the content of the register Y.</p><p>TYA does not affect any other register other than the accumulator and does not affect the carry or overflow flag. If the result in the accumulator A has bit 7 on, the N flag is set, otherwise it is reset. If the resultant value in the accumulator A is 0, then the Z flag is set, otherwise it is reset.</p>",
                 "tooltip": "Transfer Index Y To Accumulator",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#TYA",
             };
@@ -404,7 +404,7 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "SHA":
             return {
-                "html": "<p>The undocumented SHA instruction performs a bit-by-bit AND operation of the following three operands: The first two are the accumulator and the index register X.</p><p>The third operand depends on the addressing mode. In the zero page indirect Y-indexed case, the third operand is the data in memory at the given zero page address (ignoring the the addressing mode's Y offset) plus 1. In the Y-indexed absolute case, it is the upper 8 bits of the given address (ignoring the the addressing mode's Y offset), plus 1.</p><p>It then transfers the result to the addressed memory location.</p><p>No flags or registers in the microprocessor are affected by the store operation.</p>",
+                "html": "<p>The undocumented SHA instruction performs a bit-by-bit AND operation of the following three operands: The first two are the accumulator and the index register X.</p><p>The third operand depends on the addressing mode. In the zero page indirect Y-indexed case, the third operand is the data in memory at the given zero page address (ignoring the addressing mode's Y offset) plus 1. In the Y-indexed absolute case, it is the upper 8 bits of the given address (ignoring the addressing mode's Y offset), plus 1.</p><p>It then transfers the result to the addressed memory location.</p><p>No flags or registers in the microprocessor are affected by the store operation.</p>",
                 "tooltip": "Store Accumulator \"AND\" Index Register X \"AND\" Value",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#SHA",
             };
@@ -488,14 +488,14 @@ export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInf
 
         case "SHX":
             return {
-                "html": "<p>The undocumented SHX instruction performs a bit-by-bit AND operation of the index register X and the upper 8 bits of the given address (ignoring the the addressing mode's Y offset), plus 1. It then transfers the result to the addressed memory location.</p><p>No flags or registers in the microprocessor are affected by the store operation.</p>",
+                "html": "<p>The undocumented SHX instruction performs a bit-by-bit AND operation of the index register X and the upper 8 bits of the given address (ignoring the addressing mode's Y offset), plus 1. It then transfers the result to the addressed memory location.</p><p>No flags or registers in the microprocessor are affected by the store operation.</p>",
                 "tooltip": "Store Index Register X \"AND\" Value",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#SHX",
             };
 
         case "SHY":
             return {
-                "html": "<p>The undocumented SHY instruction performs a bit-by-bit AND operation of the index register Y and the upper 8 bits of the given address (ignoring the the addressing mode's X offset), plus 1. It then transfers the result to the addressed memory location.</p><p>No flags or registers in the microprocessor are affected by the store operation.</p>",
+                "html": "<p>The undocumented SHY instruction performs a bit-by-bit AND operation of the index register Y and the upper 8 bits of the given address (ignoring the addressing mode's X offset), plus 1. It then transfers the result to the addressed memory location.</p><p>No flags or registers in the microprocessor are affected by the store operation.</p>",
                 "tooltip": "Store Index Register Y \"AND\" Value",
                 "url": "https://www.pagetable.com/c64ref/6502/?cpu=6502&tab=2#SHY",
             };
diff --git a/lib/asm-docs/generated/asm-docs-65c816.ts b/lib/asm-docs/generated/asm-docs-65c816.ts
new file mode 100644
index 000000000..94fdb35da
--- /dev/null
+++ b/lib/asm-docs/generated/asm-docs-65c816.ts
@@ -0,0 +1,644 @@
+import {AssemblyInstructionInfo} from '../base.js';
+
+export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInfo | undefined {
+    if (!opcode) return;
+    switch (opcode.toUpperCase()) {
+        case "ADC":
+            return {
+                "html": "<p>Add Memory to Accumulator with Carry</p>",
+                "tooltip": "Add Memory to Accumulator with Carry",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#ADC",
+            };
+
+        case "AND":
+            return {
+                "html": "<p>\"AND\" Memory with Accumulator</p>",
+                "tooltip": "\"AND\" Memory with Accumulator",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#AND",
+            };
+
+        case "ASL":
+            return {
+                "html": "<p>Arithmetic Shift Left</p>",
+                "tooltip": "Arithmetic Shift Left",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#ASL",
+            };
+
+        case "BCC":
+            return {
+                "html": "<p>Branch on Carry Clear</p>",
+                "tooltip": "Branch on Carry Clear",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#BCC",
+            };
+
+        case "BCS":
+            return {
+                "html": "<p>Branch on Carry Set</p>",
+                "tooltip": "Branch on Carry Set",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#BCS",
+            };
+
+        case "BEQ":
+            return {
+                "html": "<p>Branch on Result Zero</p>",
+                "tooltip": "Branch on Result Zero",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#BEQ",
+            };
+
+        case "BIT":
+            return {
+                "html": "<p>Test Bits in Memory with Accumulator</p>",
+                "tooltip": "Test Bits in Memory with Accumulator",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#BIT",
+            };
+
+        case "BMI":
+            return {
+                "html": "<p>Branch on Result Minus</p>",
+                "tooltip": "Branch on Result Minus",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#BMI",
+            };
+
+        case "BNE":
+            return {
+                "html": "<p>Branch on Result Not Zero</p>",
+                "tooltip": "Branch on Result Not Zero",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#BNE",
+            };
+
+        case "BPL":
+            return {
+                "html": "<p>Branch on Result Plus</p>",
+                "tooltip": "Branch on Result Plus",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#BPL",
+            };
+
+        case "BRK":
+            return {
+                "html": "<p>Break Command</p>",
+                "tooltip": "Break Command",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#BRK",
+            };
+
+        case "BVC":
+            return {
+                "html": "<p>Branch on Overflow Clear</p>",
+                "tooltip": "Branch on Overflow Clear",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#BVC",
+            };
+
+        case "BVS":
+            return {
+                "html": "<p>Branch on Overflow Set</p>",
+                "tooltip": "Branch on Overflow Set",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#BVS",
+            };
+
+        case "CLC":
+            return {
+                "html": "<p>Clear Carry Flag</p>",
+                "tooltip": "Clear Carry Flag",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#CLC",
+            };
+
+        case "CLD":
+            return {
+                "html": "<p>Clear Decimal Mode</p>",
+                "tooltip": "Clear Decimal Mode",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#CLD",
+            };
+
+        case "CLI":
+            return {
+                "html": "<p>Clear Interrupt Disable</p>",
+                "tooltip": "Clear Interrupt Disable",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#CLI",
+            };
+
+        case "CLV":
+            return {
+                "html": "<p>Clear Overflow Flag</p>",
+                "tooltip": "Clear Overflow Flag",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#CLV",
+            };
+
+        case "CMP":
+            return {
+                "html": "<p>Compare Memory and Accumulator</p>",
+                "tooltip": "Compare Memory and Accumulator",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#CMP",
+            };
+
+        case "CPX":
+            return {
+                "html": "<p>Compare Index Register X To Memory</p>",
+                "tooltip": "Compare Index Register X To Memory",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#CPX",
+            };
+
+        case "CPY":
+            return {
+                "html": "<p>Compare Index Register Y To Memory</p>",
+                "tooltip": "Compare Index Register Y To Memory",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#CPY",
+            };
+
+        case "DEC":
+            return {
+                "html": "<p>Decrement Memory By One</p>",
+                "tooltip": "Decrement Memory By One",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#DEC",
+            };
+
+        case "DEX":
+            return {
+                "html": "<p>Decrement Index Register X By One</p>",
+                "tooltip": "Decrement Index Register X By One",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#DEX",
+            };
+
+        case "DEY":
+            return {
+                "html": "<p>Decrement Index Register Y By One</p>",
+                "tooltip": "Decrement Index Register Y By One",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#DEY",
+            };
+
+        case "EOR":
+            return {
+                "html": "<p>\"Exclusive OR\" Memory with Accumulator</p>",
+                "tooltip": "\"Exclusive OR\" Memory with Accumulator",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#EOR",
+            };
+
+        case "INC":
+            return {
+                "html": "<p>Increment Memory By One</p>",
+                "tooltip": "Increment Memory By One",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#INC",
+            };
+
+        case "INX":
+            return {
+                "html": "<p>Increment Index Register X By One</p>",
+                "tooltip": "Increment Index Register X By One",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#INX",
+            };
+
+        case "INY":
+            return {
+                "html": "<p>Increment Index Register Y By One</p>",
+                "tooltip": "Increment Index Register Y By One",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#INY",
+            };
+
+        case "JMP":
+            return {
+                "html": "<p>JMP Indirect</p>",
+                "tooltip": "JMP Indirect",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#JMP",
+            };
+
+        case "JSR":
+            return {
+                "html": "<p>Jump To Subroutine</p>",
+                "tooltip": "Jump To Subroutine",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#JSR",
+            };
+
+        case "LDA":
+            return {
+                "html": "<p>Load Accumulator with Memory</p>",
+                "tooltip": "Load Accumulator with Memory",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#LDA",
+            };
+
+        case "LDX":
+            return {
+                "html": "<p>Load Index Register X From Memory</p>",
+                "tooltip": "Load Index Register X From Memory",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#LDX",
+            };
+
+        case "LDY":
+            return {
+                "html": "<p>Load Index Register Y From Memory</p>",
+                "tooltip": "Load Index Register Y From Memory",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#LDY",
+            };
+
+        case "LSR":
+            return {
+                "html": "<p>Logical Shift Right</p>",
+                "tooltip": "Logical Shift Right",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#LSR",
+            };
+
+        case "NOP":
+            return {
+                "html": "<p>No Operation</p>",
+                "tooltip": "No Operation",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#NOP",
+            };
+
+        case "ORA":
+            return {
+                "html": "<p>\"OR\" Memory with Accumulator</p>",
+                "tooltip": "\"OR\" Memory with Accumulator",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#ORA",
+            };
+
+        case "PHA":
+            return {
+                "html": "<p>Push Accumulator On Stack</p>",
+                "tooltip": "Push Accumulator On Stack",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PHA",
+            };
+
+        case "PHP":
+            return {
+                "html": "<p>Push Processor Status On Stack</p>",
+                "tooltip": "Push Processor Status On Stack",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PHP",
+            };
+
+        case "PLA":
+            return {
+                "html": "<p>Pull Accumulator From Stack</p>",
+                "tooltip": "Pull Accumulator From Stack",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PLA",
+            };
+
+        case "PLP":
+            return {
+                "html": "<p>Pull Processor Status From Stack</p>",
+                "tooltip": "Pull Processor Status From Stack",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PLP",
+            };
+
+        case "ROL":
+            return {
+                "html": "<p>Rotate Left</p>",
+                "tooltip": "Rotate Left",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#ROL",
+            };
+
+        case "ROR":
+            return {
+                "html": "<p>Rotate Right</p>",
+                "tooltip": "Rotate Right",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#ROR",
+            };
+
+        case "RTI":
+            return {
+                "html": "<p>Return From Interrupt</p>",
+                "tooltip": "Return From Interrupt",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#RTI",
+            };
+
+        case "RTS":
+            return {
+                "html": "<p>Return From Subroutine</p>",
+                "tooltip": "Return From Subroutine",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#RTS",
+            };
+
+        case "SBC":
+            return {
+                "html": "<p>Subtract Memory from Accumulator with Borrow</p>",
+                "tooltip": "Subtract Memory from Accumulator with Borrow",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#SBC",
+            };
+
+        case "SEC":
+            return {
+                "html": "<p>Set Carry Flag</p>",
+                "tooltip": "Set Carry Flag",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#SEC",
+            };
+
+        case "SED":
+            return {
+                "html": "<p>Set Decimal Mode</p>",
+                "tooltip": "Set Decimal Mode",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#SED",
+            };
+
+        case "SEI":
+            return {
+                "html": "<p>Set Interrupt Disable</p>",
+                "tooltip": "Set Interrupt Disable",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#SEI",
+            };
+
+        case "STA":
+            return {
+                "html": "<p>Store Accumulator in Memory</p>",
+                "tooltip": "Store Accumulator in Memory",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#STA",
+            };
+
+        case "STX":
+            return {
+                "html": "<p>Store Index Register X In Memory</p>",
+                "tooltip": "Store Index Register X In Memory",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#STX",
+            };
+
+        case "STY":
+            return {
+                "html": "<p>Store Index Register Y In Memory</p>",
+                "tooltip": "Store Index Register Y In Memory",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#STY",
+            };
+
+        case "TAX":
+            return {
+                "html": "<p>Transfer Accumulator To Index X</p>",
+                "tooltip": "Transfer Accumulator To Index X",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#TAX",
+            };
+
+        case "TAY":
+            return {
+                "html": "<p>Transfer Accumulator To Index Y</p>",
+                "tooltip": "Transfer Accumulator To Index Y",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#TAY",
+            };
+
+        case "TSX":
+            return {
+                "html": "<p>Transfer Stack Pointer To Index X</p>",
+                "tooltip": "Transfer Stack Pointer To Index X",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#TSX",
+            };
+
+        case "TXA":
+            return {
+                "html": "<p>Transfer Index X To Accumulator</p>",
+                "tooltip": "Transfer Index X To Accumulator",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#TXA",
+            };
+
+        case "TXS":
+            return {
+                "html": "<p>Transfer Index X To Stack Pointer</p>",
+                "tooltip": "Transfer Index X To Stack Pointer",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#TXS",
+            };
+
+        case "TYA":
+            return {
+                "html": "<p>Transfer Index Y To Accumulator</p>",
+                "tooltip": "Transfer Index Y To Accumulator",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#TYA",
+            };
+
+        case "BRA":
+            return {
+                "html": "<p>Branch Always</p>",
+                "tooltip": "Branch Always",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#BRA",
+            };
+
+        case "PHX":
+            return {
+                "html": "<p>Push Index Register X On Stack</p>",
+                "tooltip": "Push Index Register X On Stack",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PHX",
+            };
+
+        case "PHY":
+            return {
+                "html": "<p>Push Index Register Y On Stack</p>",
+                "tooltip": "Push Index Register Y On Stack",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PHY",
+            };
+
+        case "PLX":
+            return {
+                "html": "<p>Pull Index Register X From Stack</p>",
+                "tooltip": "Pull Index Register X From Stack",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PLX",
+            };
+
+        case "PLY":
+            return {
+                "html": "<p>Pull Index Register Y From Stack</p>",
+                "tooltip": "Pull Index Register Y From Stack",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PLY",
+            };
+
+        case "STZ":
+            return {
+                "html": "<p>Store Zero In Memory</p>",
+                "tooltip": "Store Zero In Memory",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#STZ",
+            };
+
+        case "TRB":
+            return {
+                "html": "<p>Test And Reset Memory Bits With Accumulator</p>",
+                "tooltip": "Test And Reset Memory Bits With Accumulator",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#TRB",
+            };
+
+        case "TSB":
+            return {
+                "html": "<p>Test And Set Memory Bits With Accumulator</p>",
+                "tooltip": "Test And Set Memory Bits With Accumulator",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#TSB",
+            };
+
+        case "BRL":
+            return {
+                "html": "<p>Branch Long</p>",
+                "tooltip": "Branch Long",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#BRL",
+            };
+
+        case "COP":
+            return {
+                "html": "<p>Coprocessor</p>",
+                "tooltip": "Coprocessor",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#COP",
+            };
+
+        case "JSL":
+            return {
+                "html": "<p>Jump to Subroutine Long</p>",
+                "tooltip": "Jump to Subroutine Long",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#JSL",
+            };
+
+        case "MVN":
+            return {
+                "html": "<p>Move Memory Negative</p>",
+                "tooltip": "Move Memory Negative",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#MVN",
+            };
+
+        case "MVP":
+            return {
+                "html": "<p>Move Memory Positive</p>",
+                "tooltip": "Move Memory Positive",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#MVP",
+            };
+
+        case "PEA":
+            return {
+                "html": "<p>Push Effective Address</p>",
+                "tooltip": "Push Effective Address",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PEA",
+            };
+
+        case "PEI":
+            return {
+                "html": "<p>Push Effective Indirect Address</p>",
+                "tooltip": "Push Effective Indirect Address",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PEI",
+            };
+
+        case "PER":
+            return {
+                "html": "<p>Push Effective Relative Address</p>",
+                "tooltip": "Push Effective Relative Address",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PER",
+            };
+
+        case "PHB":
+            return {
+                "html": "<p>Push Data Bank Register</p>",
+                "tooltip": "Push Data Bank Register",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PHB",
+            };
+
+        case "PHD":
+            return {
+                "html": "<p>Push Direct Register</p>",
+                "tooltip": "Push Direct Register",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PHD",
+            };
+
+        case "PHK":
+            return {
+                "html": "<p>Push K Register</p>",
+                "tooltip": "Push K Register",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PHK",
+            };
+
+        case "PLB":
+            return {
+                "html": "<p>Pull Data Bank Register</p>",
+                "tooltip": "Pull Data Bank Register",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PLB",
+            };
+
+        case "PLD":
+            return {
+                "html": "<p>Pull Direct Register</p>",
+                "tooltip": "Pull Direct Register",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#PLD",
+            };
+
+        case "REP":
+            return {
+                "html": "<p>Reset Processor Status Bits</p>",
+                "tooltip": "Reset Processor Status Bits",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#REP",
+            };
+
+        case "RTL":
+            return {
+                "html": "<p>Return From Subroutine Long</p>",
+                "tooltip": "Return From Subroutine Long",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#RTL",
+            };
+
+        case "SEP":
+            return {
+                "html": "<p>Set Processor Status Bits</p>",
+                "tooltip": "Set Processor Status Bits",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#SEP",
+            };
+
+        case "STP":
+            return {
+                "html": "<p>Stop the Clock</p>",
+                "tooltip": "Stop the Clock",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#STP",
+            };
+
+        case "TCD":
+            return {
+                "html": "<p>Transfer C Accumulator to Direct Register</p>",
+                "tooltip": "Transfer C Accumulator to Direct Register",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#TCD",
+            };
+
+        case "TCS":
+            return {
+                "html": "<p>Transfer C Accumulator to Stack Pointer</p>",
+                "tooltip": "Transfer C Accumulator to Stack Pointer",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#TCS",
+            };
+
+        case "TDC":
+            return {
+                "html": "<p>Transfer Direct Register to C Accumulator</p>",
+                "tooltip": "Transfer Direct Register to C Accumulator",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#TDC",
+            };
+
+        case "TSC":
+            return {
+                "html": "<p>Transfer Stack Pointer to C Accumulator</p>",
+                "tooltip": "Transfer Stack Pointer to C Accumulator",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#TSC",
+            };
+
+        case "TXY":
+            return {
+                "html": "<p>Transfer X to Y</p>",
+                "tooltip": "Transfer X to Y",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#TXY",
+            };
+
+        case "TYX":
+            return {
+                "html": "<p>Transfer Y to X</p>",
+                "tooltip": "Transfer Y to X",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#TYX",
+            };
+
+        case "WAI":
+            return {
+                "html": "<p>Wait for Interrupt</p>",
+                "tooltip": "Wait for Interrupt",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#WAI",
+            };
+
+        case "WDM":
+            return {
+                "html": "<p>William D. Mensch, Jr.</p>",
+                "tooltip": "William D. Mensch, Jr.",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#WDM",
+            };
+
+        case "XBA":
+            return {
+                "html": "<p>Exchange B and A Accumulator</p>",
+                "tooltip": "Exchange B and A Accumulator",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#XBA",
+            };
+
+        case "XCE":
+            return {
+                "html": "<p>Exchange Carry and Emulation Flags</p>",
+                "tooltip": "Exchange Carry and Emulation Flags",
+                "url": "https://www.pagetable.com/c64ref/6502/?cpu=65c816&tab=2#XCE",
+            };
+
+    }
+}
\ No newline at end of file
diff --git a/lib/asm-docs/wdc65c816.ts b/lib/asm-docs/wdc65c816.ts
new file mode 100644
index 000000000..9bfeed303
--- /dev/null
+++ b/lib/asm-docs/wdc65c816.ts
@@ -0,0 +1,35 @@
+// Copyright (c) 2025, Compiler Explorer Authors
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//     * Redistributions of source code must retain the above copyright notice,
+//       this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above copyright
+//       notice, this list of conditions and the following disclaimer in the
+//       documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+import {AssemblyInstructionInfo, BaseAssemblyDocumentationProvider} from './base.js';
+import {getAsmOpcode} from './generated/asm-docs-65c816.js';
+
+export class WDC65c816DocumentationProvider extends BaseAssemblyDocumentationProvider {
+    public static get key() {
+        return 'wdc65c816';
+    }
+    public override getInstructionInformation(instruction: string): AssemblyInstructionInfo | null {
+        return getAsmOpcode(instruction) || null;
+    }
+}
diff --git a/lib/base-compiler.ts b/lib/base-compiler.ts
index 591b10985..63b8a826a 100644
--- a/lib/base-compiler.ts
+++ b/lib/base-compiler.ts
@@ -2150,7 +2150,7 @@ export class BaseCompiler {
         }
 
         const execTriple = await RemoteExecutionQuery.guessExecutionTripleForBuildresult(buildResult);
-        if (!matchesCurrentHost(execTriple)) {
+        if (!this.compiler.emulated && !matchesCurrentHost(execTriple)) {
             if (await RemoteExecutionQuery.isPossible(execTriple)) {
                 const result = await this.runExecutableRemotely(executablePackageHash, executeParameters, execTriple);
                 return moveArtifactsIntoResult(buildResult, {
diff --git a/lib/compiler-finder.ts b/lib/compiler-finder.ts
index d40fcafaa..477f7a512 100644
--- a/lib/compiler-finder.ts
+++ b/lib/compiler-finder.ts
@@ -203,6 +203,7 @@ export class CompilerFinder {
 
         const supportsBinary = !!props('supportsBinary', true);
         const supportsBinaryObject = !!props('supportsBinaryObject', false);
+        const emulated = !!props('emulated', false);
         const interpreted = !!props('interpreted', false);
         const supportsExecute = (interpreted || supportsBinary) && !!props('supportsExecute', true);
         const executionWrapper = props('executionWrapper', '');
@@ -278,6 +279,7 @@ export class CompilerFinder {
             supportsDemangle: !!demangler,
             supportsBinary,
             supportsBinaryObject,
+            emulated,
             interpreted,
             supportsExecute,
             executionWrapper,
diff --git a/lib/compilers/_all.ts b/lib/compilers/_all.ts
index 5131a27e4..230f87529 100644
--- a/lib/compilers/_all.ts
+++ b/lib/compilers/_all.ts
@@ -109,6 +109,7 @@ export {NvccCompiler} from './nvcc.js';
 export {NvcppCompiler} from './nvcpp.js';
 export {NvrtcCompiler} from './nvrtc.js';
 export {OCamlCompiler} from './ocaml.js';
+export {ORCACompiler} from './orca.js';
 export {OSACATool} from './osaca.js';
 export {OdinCompiler} from './odin.js';
 export {OptCompiler} from './opt.js';
diff --git a/lib/compilers/orca.ts b/lib/compilers/orca.ts
new file mode 100644
index 000000000..88698f6bc
--- /dev/null
+++ b/lib/compilers/orca.ts
@@ -0,0 +1,91 @@
+// Copyright (c) 2025, Compiler Explorer Authors
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//     * Redistributions of source code must retain the above copyright notice,
+//       this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above copyright
+//       notice, this list of conditions and the following disclaimer in the
+//       documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+import path from 'node:path';
+
+import {BypassCache, CacheKey, CompilationResult} from '../../types/compilation/compilation.interfaces.js';
+import type {PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
+import {ExecutableExecutionOptions} from '../../types/execution/execution.interfaces.js';
+import type {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
+import {BaseCompiler} from '../base-compiler.js';
+import {CompilationEnvironment} from '../compilation-env.js';
+import {ORCAAsmParser} from '../parsers/asm-parser-orca.js';
+import * as utils from '../utils.js';
+
+export class ORCACompiler extends BaseCompiler {
+    static get key() {
+        return 'orca';
+    }
+
+    goldenGate: string;
+
+    constructor(compilerInfo: PreliminaryCompilerInfo, env: CompilationEnvironment) {
+        super(compilerInfo, env);
+        this.goldenGate = this.compilerProps<string>(`compiler.${this.compiler.id}.goldenGate`);
+        this.asm = new ORCAAsmParser(this.compilerProps);
+        this.compiler.demangler = '';
+        this.demanglerClass = null;
+    }
+
+    override getDefaultExecOptions() {
+        const execOptions = super.getDefaultExecOptions();
+        if (this.goldenGate) {
+            execOptions.env.GOLDEN_GATE = this.goldenGate;
+        }
+
+        return execOptions;
+    }
+
+    override getOutputFilename(dirPath: string, outputFilebase: string) {
+        return path.join(dirPath, `${outputFilebase}.a`);
+    }
+
+    override getSharedLibraryPathsAsArguments() {
+        return [];
+    }
+
+    override optionsForFilter(filters: ParseFiltersAndOutputOptions, outputFilename: string, userOptions?: string[]) {
+        let options: string[];
+
+        if (filters.binary) {
+            options = ['cmpl', 'keep=' + this.filename(outputFilename)];
+        } else {
+            filters.binaryObject = true;
+            options = ['compile', 'keep=' + this.filename(utils.changeExtension(outputFilename, ''))];
+        }
+
+        return options;
+    }
+
+    override async handleExecution(
+        key: CacheKey,
+        executeParameters: ExecutableExecutionOptions,
+        bypassCache: BypassCache,
+    ): Promise<CompilationResult> {
+        if (this.goldenGate) {
+            executeParameters.env.GOLDEN_GATE = this.goldenGate;
+        }
+        return super.handleExecution(key, executeParameters, bypassCache);
+    }
+}
diff --git a/lib/exec.ts b/lib/exec.ts
index 1afd2584e..e104c7008 100644
--- a/lib/exec.ts
+++ b/lib/exec.ts
@@ -26,6 +26,9 @@ import buffer from 'buffer';
 import child_process from 'node:child_process';
 import os from 'node:os';
 import path from 'node:path';
+// @ts-ignore
+import which from 'which';
+
 import {Stream} from 'node:stream';
 
 import fs from 'fs-extra';
@@ -35,6 +38,7 @@ import _ from 'underscore';
 import type {ExecutionOptions} from '../types/compilation/compilation.interfaces.js';
 import type {FilenameTransformFunc, UnprocessedExecResult} from '../types/execution/execution.interfaces.js';
 
+import {splitArguments} from '../shared/common-utils.js';
 import {assert, unwrap, unwrapString} from './assert.js';
 import {logger} from './logger.js';
 import {Graceful} from './node-graceful.js';
@@ -49,6 +53,8 @@ type NsJailOptions = {
 
 const execProps = propsFor('execution');
 
+let stdbufPath = null;
+
 function checkExecOptions(options: ExecutionOptions) {
     if (options.env) {
         for (const key of Object.keys(options.env)) {
@@ -68,7 +74,7 @@ function setupOnError(stream: Stream, name: string) {
     });
 }
 
-export function executeDirect(
+export async function executeDirect(
     command: string,
     args: string[],
     options: ExecutionOptions,
@@ -91,6 +97,20 @@ export function executeDirect(
         if (command.startsWith('./')) command = path.join(process.cwd(), command);
     }
 
+    if (stdbufPath == null) {
+        const unbufferStdoutExe = execProps<string>('unbufferStdoutExe', undefined); // by default 'stdout'
+        if (unbufferStdoutExe) {
+            stdbufPath = await which(unbufferStdoutExe);
+            if (!stdbufPath) logger.error(`Could not find ${unbufferStdoutExe} in PATH`);
+        }
+    }
+
+    if (stdbufPath) {
+        const stdbufArgs = splitArguments(execProps<string>('unbufferStdoutArgs', undefined)); // by default ['-o0']
+        args.unshift(...stdbufArgs, command);
+        command = stdbufPath;
+    }
+
     let okToCache = true;
     let timedOut = false;
     // In WSL; run Windows-volume executables in a temp directory.
diff --git a/lib/instructionsets.ts b/lib/instructionsets.ts
index 19e576f51..117ad6c47 100644
--- a/lib/instructionsets.ts
+++ b/lib/instructionsets.ts
@@ -131,6 +131,10 @@ export class InstructionSets {
                 target: [],
                 path: [],
             },
+            wdc65c816: {
+                target: [],
+                path: [],
+            },
             core: {
                 target: [],
                 path: [],
diff --git a/lib/objdumper/_all.ts b/lib/objdumper/_all.ts
index 347831e35..ae8681792 100644
--- a/lib/objdumper/_all.ts
+++ b/lib/objdumper/_all.ts
@@ -27,3 +27,4 @@ export {DefaultObjdumper} from './default.js';
 export {ElfToolChainObjdumper} from './elftoolchain.js';
 export {LlvmObjdumper} from './llvm.js';
 export {Da65Objdumper} from './da65.js';
+export {GoldenGateObjdumper} from './goldengate.js';
diff --git a/lib/objdumper/goldengate.ts b/lib/objdumper/goldengate.ts
new file mode 100644
index 000000000..a97664897
--- /dev/null
+++ b/lib/objdumper/goldengate.ts
@@ -0,0 +1,39 @@
+// Copyright (c) 2025, Compiler Explorer Authors
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//     * Redistributions of source code must retain the above copyright notice,
+//       this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above copyright
+//       notice, this list of conditions and the following disclaimer in the
+//       documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+import {BaseObjdumper} from './base.js';
+
+export class GoldenGateObjdumper extends BaseObjdumper {
+    constructor() {
+        super([], []);
+    }
+
+    override getDefaultArgs(outputFilename: string) {
+        return [outputFilename];
+    }
+
+    static override get key() {
+        return 'goldengate';
+    }
+}
diff --git a/lib/parsers/asm-parser-orca.ts b/lib/parsers/asm-parser-orca.ts
new file mode 100644
index 000000000..40e3cf708
--- /dev/null
+++ b/lib/parsers/asm-parser-orca.ts
@@ -0,0 +1,149 @@
+// Copyright (c) 2025, Compiler Explorer Authors
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//     * Redistributions of source code must retain the above copyright notice,
+//       this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above copyright
+//       notice, this list of conditions and the following disclaimer in the
+//       documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+import {AsmResultLabel, ParsedAsmResultLine} from '../../types/asmresult/asmresult.interfaces.js';
+import {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
+import {PropertyGetter} from '../properties.interfaces.js';
+
+import {AsmParser} from './asm-parser.js';
+
+export class ORCAAsmParser extends AsmParser {
+    labelDefinitionRe: RegExp;
+    operandRe: RegExp;
+    labelInOperandRe: RegExp;
+    directiveRe: RegExp;
+    linePreCommentRe: RegExp;
+    labelOpcodeOperandRe: RegExp;
+    buggyLabelRe: RegExp;
+
+    constructor(compilerProps: PropertyGetter) {
+        super(compilerProps);
+
+        this.commentRe = /^[!*;]\s.*/;
+        this.labelDefinitionRe = /^([A-Z_a-z~][\w~]*)/;
+        this.operandRe = /^((?:[A-Z_a-z~][\w~]*)?\s+[A-Za-z]{3}\s+)([^;]+)/;
+        this.labelInOperandRe = /^[#(>|]*([A-Z_a-z~][\w~]*)/;
+        this.directiveRe =
+            /^\s+(?:align|anop|case|codechk|datachk|dynchk|eject|err|expand|ieee|instime|keep|kind|list|longa|longi|mem|merr|msb|numsex|objcase|printer|setcom|symbol|title|65c02|65816)\s+/;
+        this.linePreCommentRe = /^(.{80}[^;]*);/;
+        this.labelOpcodeOperandRe = /^((?:[A-Z_a-z~][\w~]*)?)\s+([\w~]+)\s*(.*)/;
+        this.buggyLabelRe = /^([\w~]{20,})(start|entry)$/;
+    }
+
+    extractLabels(line: string): AsmResultLabel[] | undefined {
+        let match = line.match(this.operandRe);
+        if (match) {
+            const preOperandLength = match[1].length;
+            const operand = match[2];
+
+            if (operand === 'a' || operand === 'A') {
+                return undefined;
+            }
+
+            match = operand.match(this.labelInOperandRe);
+            if (match) {
+                const labelsInLine: AsmResultLabel[] = [];
+
+                const label = match[1];
+
+                const startCol = preOperandLength + operand.indexOf(label) + 1;
+                labelsInLine.push({
+                    name: label,
+                    range: {
+                        startCol: startCol,
+                        endCol: startCol + label.length,
+                    },
+                });
+
+                return labelsInLine;
+            }
+        }
+
+        return undefined;
+    }
+
+    override processBinaryAsm(asm: string, filters: ParseFiltersAndOutputOptions) {
+        const result: ParsedAsmResultLine[] = [];
+        const asmLines = asm.split('\n');
+
+        const labelDefinitions: Record<string, number> = {};
+
+        for (let line of asmLines) {
+            let match = line.match(this.commentRe);
+            if (match) {
+                if (!filters.commentOnly) {
+                    result.push({
+                        text: line,
+                    });
+                }
+                continue;
+            }
+
+            // Insert missing spaces after long labels.
+            // These may be omitted due to a bug in Golden Gate's dumpobj.
+            match = line.match(this.buggyLabelRe);
+            if (match) {
+                line = match[1] + ' ' + match[2];
+            }
+
+            match = line.match(this.labelDefinitionRe);
+            if (match) {
+                labelDefinitions[match[1]] = result.length + 1;
+            }
+
+            if (filters.commentOnly || filters.trim) {
+                match = line.match(this.linePreCommentRe);
+                if (match) {
+                    line = match[1];
+                }
+            }
+
+            if (filters.directives) {
+                match = line.toLowerCase().match(this.directiveRe);
+                if (match) continue;
+            }
+
+            if (filters.trim) {
+                match = line.match(this.labelOpcodeOperandRe);
+                if (match) {
+                    line = match[1] + (match[1].length === 0 ? '  ' : ' ') + match[2] + ' ' + match[3];
+                }
+            }
+
+            if (result.length === 0 || (filters.trim && result[result.length - 1].text.trim() !== 'end')) {
+                if (line.trim() === '') continue;
+            }
+
+            result.push({
+                text: line.trimEnd(),
+                labels: this.extractLabels(line),
+            });
+        }
+
+        return {
+            asm: result,
+            labelDefinitions: labelDefinitions,
+        };
+    }
+}
diff --git a/types/compiler.interfaces.ts b/types/compiler.interfaces.ts
index fe99265b2..a5331c876 100644
--- a/types/compiler.interfaces.ts
+++ b/types/compiler.interfaces.ts
@@ -70,6 +70,7 @@ export type CompilerInfo = {
     supportsBinary?: boolean;
     supportsBinaryObject?: boolean;
     supportsIntel?: boolean;
+    emulated?: boolean;
     interpreted?: boolean;
     // (interpreted || supportsBinary) && supportsExecute
     supportsExecute?: boolean;
diff --git a/types/instructionsets.ts b/types/instructionsets.ts
index 733e82671..f116a5d9e 100644
--- a/types/instructionsets.ts
+++ b/types/instructionsets.ts
@@ -59,6 +59,7 @@ export const InstructionSetsList = [
     'vax',
     'wasm32',
     'wasm64',
+    'wdc65c816',
     'xtensa',
     'z80',
 ] as const;


Test patch:
diff --git a/test/handlers/asm-docs-tests.ts b/test/handlers/asm-docs-tests.ts
index 274ae73c9..7d9318eb0 100644
--- a/test/handlers/asm-docs-tests.ts
+++ b/test/handlers/asm-docs-tests.ts
@@ -104,6 +104,14 @@ const TEST_MATRIX: Record<PropertyKey, [string, string, string, string][]> = {
         ],
     ],
     sass: [['FADD', 'FP32 Add', 'FP32 Add', 'https://docs.nvidia.com/cuda/cuda-binary-utilities/index.html#id14']],
+    wdc65c816: [
+        [
+            'jsl',
+            'Jump to Subroutine Long',
+            '<p>Jump to Subroutine Long</p>',
+            'https://www.pagetable.com/c64ref/6502/?cpu=65c816',
+        ],
+    ],
 };
 
 describe('Assembly Documentation API', () => {