{"id":28451702,"url":"https://github.com/kcxt/6502.sh","last_synced_at":"2026-05-13T05:34:10.775Z","repository":{"id":283153188,"uuid":"949374777","full_name":"kcxt/6502.sh","owner":"kcxt","description":" A 6502 emulator written in busybox ash","archived":false,"fork":false,"pushed_at":"2025-03-18T19:51:00.000Z","size":108,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-06T16:11:43.718Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Assembly","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kcxt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-03-16T10:12:11.000Z","updated_at":"2025-04-19T01:49:40.000Z","dependencies_parsed_at":null,"dependency_job_id":"f77d975c-83d2-4e63-8ae9-dad95e3c1655","html_url":"https://github.com/kcxt/6502.sh","commit_stats":null,"previous_names":["calebccff/6502.sh","kcxt/6502.sh"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kcxt/6502.sh","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kcxt%2F6502.sh","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kcxt%2F6502.sh/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kcxt%2F6502.sh/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kcxt%2F6502.sh/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kcxt","download_url":"https://codeload.github.com/kcxt/6502.sh/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kcxt%2F6502.sh/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263069213,"owners_count":23408914,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-06T16:11:40.215Z","updated_at":"2026-05-13T05:34:10.726Z","avatar_url":"https://github.com/kcxt.png","language":"Assembly","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ./6502.sh\n\n6502.sh is a fully-functional 6502 emulator and debugger written in [busybox\nash](https://linux.die.net/man/1/ash) compliant shell script, using only a\nhandful of busybox tools.\n\n## Features\n\n6502.sh has a whopping 32k of RAM and 16k ROM in its default configuration,\nhowever this can be easily adjusted by editing [`machine.sh`](/machine.sh).\n\nIt includes an interactive debugger with single-stepping, breakpoints (break on\ncode, data access, JSR/RTS), and more. See [#Debugger](#debugger) for detailed\ninstructions.\n\nSTDIO is directed to an ACIA compatible serial port at `$8400` allowing for\nprograms like BASIC to run.\n\nLaunching with the `-d` flag will make 6502.sh output additional info about the\ninstructions being executed to a socket (`/tmp/65sh.sock`). You can watch this\nlog by running [`./watch.sh`](/watch.sh).\n\n## Requirements\n\nThe dasm compiler is required for building wozmon and the unit tests. cc65 is\nrequired for BASIC.\n\n## Usage\n\n```shell\n$ ./6502.sh ./progs/basic/basic.bin\nLoading ./progs/basic/basic.bin...\nReset vector: $E836\n\n6502 EhBASIC [C]old/[W]arm ? c\n\nMemory size ? 32768\n\n31999 Bytes free\n\nEnhanced BASIC 2.22p5\n\nReady\n10 PRINT \"HI FROM 6502.SH\"\n20 GOTO 10\nRUN\nHI FROM 6502.SH\nHI FROM 6502.SH\nHI FROM 6502.SH\nHI FROM 6502.SH\n\u003e Dropping into debug monitor\nStatus: $36\n    negative : 0\n    overflow : 0\n    constant : 1\n    break    : 1\n    decimal  : 0\n    interrupt: 1\n    zero     : 1\n    carry    : 0\nRegisters:\n    A : $00\n    X : $DF\n    Y : $02\n    SP: $FF\n    PC: $C4C3\nRan 31204 instructions\n65sh\u003e \n\n```\n\nUnit tests can be run with [`test.sh`](/test.sh), they live in the tests\nsubdirectory.\n\nSome example programs can be found in [`progs`](/progs/):\n\n* wozmon - A port of the Apple I monitor\n* basic - Enhanced BASIC port (compile with `make`, cc65 is required)\n\nAny DASM compatible assembly can be built with `./build.sh path/to/source.asm`,\nthe resulting binary is placed in `build/`, e.g.\n\n```shell\n$ ./build.sh progs/wozmon.asm\n\nComplete. (0)\n```\n\n## TODO\n\n* Emulate more hardware? Disk?\n* Plugin system for hardware modules\n* Performance optimisations (JIT to shell?)\n\n### Serial port\n\nAn ACIA compatible serial port is emulated. Tx delay loops are NOT recommended\nhere as they only serve to slow the emulator down.\n\nFor each opcode executed, the emulator checks for input on stdin and buffers a\nsingle character that can be read from `$8400` by the emulated program. Output\nis available by writing a character to the same address. You can check if a\ncharacter is pending by reading `$8401` and checking bit 3 (value `$08`).\n\n### Additional registers\n\n| Address | Name      | R/W | Description |\n|---------|-----------|-----|-------------|\n| `$8010` | ASSERT    |  WO | Writes will trigger a test assert. This is used for unit tests which describe the expected state of the machine at the start of the test ROM. |\n| `$8040` | HALT      |  WO | Writes will halt execution and drop to the debugger. |\n\n### Trap\n\nWrites of any value to `$8040` act as a trap or breakpoint and cause the\nemulator to pause execution and drop to the monitor (described below).\n\nAlternatively, executing any branching instruction that sets the program counter\nto point to itself (causing an infinite loop) will also cause a trap.\n\nFinally, pressing the backtick key (`\\``) will always cause the emulator to\ntrap.\n\nIn call cases the emulator will drop to the debugger `65sh\u003e`.\n\n### Debugger\n\n6502.sh includes a built-in monitor/debugger which you can drop to by pressing\nthe `backtick` '\\`' key on your keyboard or via a trap in the program (described\nabove). You can also halt before execution by launching *6502.sh* with the `-d`\nflag.\n\n\u003e **NOTE:** Unlike in GDB, ctrl+c will cause the emulator to exit rather than\n\u003e trap into the debugger.\n\n```txt\nLoading ./build/fibonacci.bin...\nReset vector: $8009\nRegisters:\n    A : $00\n    X : $00\n    Y : $00\n    PC: $8009\nRan 0 instructions\n65sh\u003e \n```\n\n#### Debug socket\n\nRun with the `-d` flag to enable the debug socket, and run `./watch.sh` in a\nseparate terminal. This will output the fetch/decode/execute internals of the\nCPU.\n\nThe format is `PC: opcode | addressing mode | instruction \u003carguments\u003e`.\n\n```txt\nC90B: $20 | ABS $E0FC       | JSR $E0FC\nE0FC: $6C | IND (=$207 )    | JMP $E865\nE865: $48 | IMP             | PHA (SP=$1F9)\nE866: $AD | ABS $8401       | LDA $8401 \u003c- $00\nE869: $68 | IMP             | PLA (A=$39 SP=$1F9)\nE86A: $8D | ABS $8400       | STA $8400 \u003c- $39\nE86D: $60 | IMP             | RTS $C90E\nC90E: $C9 | IMM $C90F       | CMP $39 $0D = $2C\nC910: $D0 | REL $C911       | BNE (Z=0) $14 (20)\nC926: $29 | IMM $C927       | AND $FF\nC928: $60 | IMP             | RTS $C8E4\nC8E4: $C8 | IMP             | INY $04\nC8E5: $CA | IMP             | DEX $01\nC8E6: $D0 | REL $C8E7       | BNE (Z=0) $F7 (-9)\nC8DF: $B1 | (71),4  = $7FFF | LDA $7FFF \u003c- $39\nC8E1: $20 | ABS $C8EE       | JSR $C8EE\nC8EE: $C9 | IMM $C8EF       | CMP $39 $20 = $19\nC8F0: $90 | REL $C8F1       | BCC (C=1) $19 (25)\nC8F2: $48 | IMP             | PHA (SP=$1FB)\nC8F3: $A5 | ZER $F          | LDA $F    \u003c- $00\nC8F5: $D0 | REL $C8F6       | BNE (Z=1) $0A (10)\nC8F7: $A5 | ZER $E          | LDA $E    \u003c- $04\n```\n\nThe debug monitor uses a GDB-like syntax, the most useful commands are:\n\n* `dt` - toggle debug output\n* `p` - dump CPU registers\n* `c` - continue execution\n* `s` - step a single instruction\n* `b`, `del ID` - add and remove breakpoints (note that the PC must be set to\n  the address in question for the breakpoint to be hit).\n* `bmem`, `del mem ID` - add/remove breakpoints based on memory access.\n\n#### Logging/self-debug\n\nThese commands configure logging or help debug the emulator itself.\n\n* `v` - enable verbose mode (`set -x`)\n* `d [CATEGORIES]` - list available debug categories (no args), or set debug\n  categories.\n* `dt` - toggle standard debug output on/off (standard categories are `INSTR`,\n  `ADDR`, `OPCODE`)\n\n#### Breakpoints\n\nThese commands manipulate breakpoints.\n\n* `b ADDR` - break just before the instruction at `ADDR` is executed\n* `bmem ADDR` - break immediately after any read or write to `ADDR`\n* `del [mem] ID` - remove breakpoint with number `ID` (or memory breakpoint\n  `ID`).\n* * `i`, `info` - list breakpoints\n\n#### Machine state\n\nThese commands allow for viewing or manipulating the machine state.\n\n* `p [VAR]` - print all CPU registers or a specific one (printed as hex)\n* `echo VAR` - `echo`\n* `set VAR VAL` - set a variable (this can be any global, usually `pc`, `a`,\n  `x`, `y`, `s` - program counter, CPU registers, stack pointer, etc)\n* `ps` - print status flags\n* `stack` - show info about the stack and stack pointer\n* `c` - continue execution\n\nThese are the available global variables (that are useful to modify), though you\nmay find joy in manipulating some of the others:\n\n* `pc` - Program counter\n* `s` - Stack pointer\n* `a`, `x`, `y` - CPU registers\n* `p` - status register (note that there are also variables for accessing the\n  individual status flags, are kept in sync with the status register and it's\n  recommended to treat them as read-only. The uppercase variants are bitmasks).\n\n#### Debug categories\n\n* INSTR - print info about the running instruction\n* MEM - show memory accesses\n* ADDR - show addressing modes / address decoding\n* OPCODE - show opcodes\n* STATUS - show changes to status bits\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkcxt%2F6502.sh","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkcxt%2F6502.sh","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkcxt%2F6502.sh/lists"}