├── .gitignore ├── COPYING.txt ├── Makefile ├── README.md ├── c65 ├── Makefile ├── README.md ├── TODO.md ├── c65.c ├── c65.h ├── fake65c02.h ├── heatmap.png ├── linenoise-win32.c ├── linenoise.c ├── linenoise.h ├── magicio.c ├── magicio.h ├── monitor.c ├── monitor.h ├── parse.c ├── parse.h ├── profile.ipynb └── tests │ ├── README.md │ ├── test.in │ ├── test.out │ ├── wozmon.asm │ ├── wozmon.rom │ └── wozmon.sym ├── definitions.asm ├── docs ├── README.md ├── WORDLIST.md ├── asciidoc_to_markdown.sh ├── ch_assembler.adoc ├── ch_bibliography.adoc ├── ch_blocks.adoc ├── ch_developing.adoc ├── ch_disasm.adoc ├── ch_editor_block.adoc ├── ch_editor_ed.adoc ├── ch_faq.adoc ├── ch_glossary.adoc ├── ch_installing.adoc ├── ch_internals.adoc ├── ch_overview.adoc ├── ch_running.adoc ├── ch_san.adoc ├── ch_tests.adoc ├── ch_thanks.adoc ├── ch_tutorial_blocks.adoc ├── ch_tutorial_ed.adoc ├── ch_tutorial_hardware.adoc ├── ch_tutorial_wordlists.adoc ├── ch_why.adoc ├── manual.adoc ├── manual.html ├── manual.md ├── manual.pdf ├── pics │ ├── Makefile │ ├── W65c02.jpg │ ├── blocks-block.png │ ├── blocks-block.txt │ ├── blocks-flush.png │ ├── blocks-flush.txt │ ├── blocks-newblock.png │ ├── blocks-newblock.txt │ ├── blocks-update.png │ ├── blocks-update.txt │ ├── blocks-update3.png │ ├── blocks-update3.txt │ ├── double_cell.png │ ├── double_cell.txt │ ├── ed_node.png │ ├── ed_node.txt │ ├── header_diagram.png │ ├── header_diagram.txt │ ├── memory_map.png │ ├── memory_map.txt │ ├── stack_diagram.png │ ├── stack_diagram.txt │ ├── tali_forth_alpha003.png │ ├── tutorial_hardware_LCD.png │ ├── tutorial_hardware_buttons_and_LEDs.png │ └── uebersquirrel.jpg ├── py65mon-labelmap.txt └── py65mon-listing.txt ├── environment.yml ├── forth_code ├── README.md ├── forth_to_ophisbin.py ├── forth_words.fs ├── test_forth_to_ophisbin.py └── user_words.fs ├── forth_examples ├── README.md └── vibe22tali.fth ├── forth_words.asc ├── old ├── README.md ├── TODO.txt ├── ch_tests.tex └── docs │ ├── bibliography.tex │ ├── ch_developing.tex │ ├── ch_faq.tex │ ├── ch_installation.tex │ ├── ch_internals.tex │ ├── ch_overview.tex │ ├── ch_running.tex │ ├── ch_tests.tex │ ├── ch_thanks.tex │ ├── ch_why.tex │ ├── manual.pdf │ └── manual.tex ├── platform ├── README.md ├── platform-apple1-ram.asm ├── platform-apple1-rom.asm ├── platform-c65.asm ├── platform-minimal.asm ├── platform-neo6502.asm ├── platform-py65mon.asm ├── platform-sbc.asm ├── platform-sorbus.asm └── platform-steckschwein.asm ├── stringtable.asm ├── taliforth-py65mon.bin ├── taliforth.asm ├── tests ├── README.md ├── asm.fs ├── benchmarks.fs ├── block.fs ├── core_a.fs ├── core_b.fs ├── core_c.fs ├── cycles.fs ├── double.fs ├── ed.fs ├── facility.fs ├── ptest.sh ├── results.txt ├── search.fs ├── string.fs ├── tali.fs ├── talitest.py ├── talitest_c65.py ├── tester.fs ├── tools.fs └── user.fs ├── tools ├── README.txt ├── code_statistics.py ├── generate_assembler.py ├── generate_glossary.py ├── generate_headers.py ├── generate_wordlist.py ├── generate_words.py ├── opcodes65c02.txt ├── reverse_asm.py ├── text_to_jason.py ├── wordsource.json └── wordsource.txt ├── user_words.asc └── words ├── README.md ├── all.asm ├── assembler.asm ├── block.asm ├── compile.asm ├── core.asm ├── disasm.asm ├── double.asm ├── ed.asm ├── editor.asm ├── headers.asm ├── string.asm ├── tali.asm ├── tools.asm └── wordlist.asm /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.pyc 3 | *.lof 4 | *.log 5 | *~ 6 | c65-*.dat 7 | c65/c65 8 | c65/c65.exe 9 | docs/minimal-*.txt 10 | docs/c65-*.txt 11 | taliforth-c65.bin 12 | taliforth-minimal.bin 13 | tests/blocks.bin -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | Tali Forth License and Copying 2 | Scot W. Stevenson 3 | First version: 07. Apr 2014 4 | This version: 18. Feb 2018 5 | 6 | Forth has a long tradition of being placed in the public domain. Tali Forth 7 | 2 for the 65c02 continues this tradition. Where external code was used, it was 8 | also from the public domain, see source code for documentation of individual 9 | routines. 10 | 11 | Tali Forth 2 for the 65c02 is provided on an "as is" basis without any warranty 12 | of any kind, including, without limitation, the implied warranties of 13 | merchantability and fitness for a particular purpose and their equivalents 14 | under the laws of any jurisdiction. Put briefly, use this at your own risk. 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Tali Forth 2 2 | # This version: 14. Jan 2020 3 | 4 | # Notes: The manual is not automatically updated because not everybody 5 | # can be expected to have the asciidoc toolchain and ditaa installed. 6 | # Tali requires python 3.x, 64tass, and GNU make to build the 65C02 7 | # binary image. 8 | 9 | # Example uses, where $ is the prompt (yours might be C:\>): 10 | # 11 | # Build tailforth-py65mon.bin for use with the py65mon simulator. 12 | # 13 | # $ make 14 | # 15 | # Build Taliforth 2 for a different platform (steckschwein shown here). 16 | # There must be a matching platform file in the platform folder. 17 | # 18 | # $ make taliforth-steckschwein.bin 19 | # 20 | # Run tests 21 | # 22 | # $ make tests 23 | # or 24 | # $ make ctests 25 | # 26 | # Build and run Taliforth 27 | # 28 | # $ make sim 29 | # or 30 | # $ make csim 31 | # 32 | # The cxxx targets use the C-based c65 simulator rather than the default 33 | # py65mon python simulator. This runs 10-100x faster but 34 | # lacks py65mon's monitor facilities for debugging. 35 | # c65 should build automatically from the sources in `c65/`. 36 | # It's been tested on posix-based systems like OS X and Windows WSL 37 | # (see https://learn.microsoft.com/en-us/windows/wsl/install). 38 | # A native Windows port for mingw is still TODO 39 | # (see https://github.com/SamCoVT/TaliForth2/issues/74). 40 | 41 | # Determine which python launcher to use (python3 on Linux and OSX, 42 | # "py -3" on Windows) and other OS-specific commands (rm vs del). 43 | ifdef OS 44 | RM = del 45 | PYTHON = py -3 46 | else 47 | RM = rm -f 48 | PYTHON = python3 49 | endif 50 | 51 | COMMON_SOURCES=taliforth.asm definitions.asm $(wildcard words/*.asm) stringtable.asm forth_words.asc user_words.asc 52 | TEST_SUITE=tests/core_a.fs tests/core_b.fs tests/core_c.fs tests/string.fs tests/double.fs \ 53 | tests/facility.fs tests/ed.fs tests/asm.fs tests/tali.fs \ 54 | tests/tools.fs tests/block.fs tests/search.fs tests/user.fs tests/cycles.fs 55 | TEST_SOURCES=tests/talitest.py $(TEST_SUITE) 56 | 57 | C65=c65/c65 58 | C65_SOURCES=c65/*.c c65/*.h 59 | 60 | all: taliforth-py65mon.bin docs/WORDLIST.md 61 | clean: 62 | $(RM) *.bin *.prg 63 | make -C c65 clean 64 | 65 | taliforth-%.bin: platform/platform-%.asm $(COMMON_SOURCES) 66 | 64tass --nostart \ 67 | --list=docs/$*-listing.txt \ 68 | --vice-labels \ 69 | --labels=docs/$*-labelmap.txt \ 70 | --output $@ \ 71 | $< 72 | 73 | taliforth-%.prg: platform/platform-%.asm $(COMMON_SOURCES) 74 | 64tass --cbm-prg \ 75 | --list=docs/$*-listing.txt \ 76 | --labels=docs/$*-labelmap.txt \ 77 | --output $@ \ 78 | $< 79 | 80 | # Convert the high-level Forth words to ASCII files that Ophis can include 81 | %.asc: forth_code/%.fs 82 | $(PYTHON) forth_code/forth_to_ophisbin.py -i $< > $@ 83 | 84 | # Automatically update the wordlist which also gives us the status of the words 85 | # We need for the binary to be generated first or else we won't be able to find 86 | # new words in the label listing 87 | docs/WORDLIST.md: tools/generate_wordlist.py taliforth-py65mon.bin 88 | $(PYTHON) tools/generate_wordlist.py > docs/WORDLIST.md 89 | 90 | 91 | # Some convenience targets to make running the tests and simulation easier. 92 | 93 | # Build the c65 simulator 94 | $(C65): $(C65_SOURCES) 95 | make -C c65 96 | 97 | # Convenience target for regular tests. 98 | tests: tests/results.txt 99 | 100 | # Run all of the tests. 101 | ctests: $(C65) taliforth-c65.bin $(TEST_SOURCES) 102 | cd tests && $(PYTHON) ./talitest_c65.py 103 | 104 | tests/results.txt: taliforth-py65mon.bin $(TEST_SOURCES) 105 | cd tests && $(PYTHON) ./talitest.py 106 | 107 | # Convenience target for parallel tests (Linux only) 108 | ptests: taliforth-py65mon.bin $(TEST_SOURCES) 109 | cd tests && ./ptest.sh 110 | 111 | # Convenience target to run the py65mon simulator. 112 | # Because taliforth-py65mon.bin is listed as a dependency, it will be 113 | # reassembled first if any changes to its sources have been made. 114 | sim: taliforth-py65mon.bin 115 | py65mon -m 65c02 -r taliforth-py65mon.bin 116 | 117 | csim: $(C65) taliforth-c65.bin 118 | $(C65) -r taliforth-c65.bin 119 | 120 | # Some convenience targets for the documentation. 121 | docs/manual.html: docs/*.adoc 122 | cd docs && asciidoctor -a toc=left manual.adoc 123 | 124 | docs/ch_glossary.adoc: tools/generate_glossary.py $(wildcard words/*.asm) 125 | $(PYTHON) tools/generate_glossary.py > docs/ch_glossary.adoc 126 | 127 | # The diagrams use ditaa to generate pretty diagrams from text files. 128 | # They have their own makefile in the docs/pics directory. 129 | docs-diagrams: docs/pics/*.txt 130 | cd docs/pics && $(MAKE) 131 | 132 | docs: docs/manual.html docs-diagrams 133 | 134 | # This one is experimental at the moment. 135 | docsmd: docs/manual.html 136 | cd docs && ./asciidoc_to_markdown.sh 137 | 138 | docspdf: docs 139 | cd docs && asciidoctor-pdf -v manual.adoc 140 | 141 | # A convenience target for preparing for a git commit. 142 | gitready: docs all ctests 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tali Forth 2 for the 65c02 2 | Scot W. Stevenson 3 | Sam Colwell 4 | Patrick Surry 5 | First version: (Tali Forth 1 ) 19. Jan 2014 6 | This version: (Version 1.1 ) 06. Apr 2024 7 | 8 | ## Dude, I am the very model of a Salarian scientist, just let me start! 9 | 10 | Run `py65mon -m 65c02 -r taliforth-py65mon.bin` from this directory. 11 | 12 | 13 | ## Introduction 14 | 15 | Tali Forth 2 is a subroutine threaded code (STC) implementation of an ANS-based 16 | Forth for the 65c02 8-bit MPU. The aim is to provide a modern Forth that is easy 17 | to get started with and can be ported to individial hardware projects, 18 | especially Single Board Computers (SBC), with little effort. It is free -- 19 | released in the public domain -- but with absolutely _no warranty_ of any kind. 20 | Use at your own risk! (See `COPYING.txt` for details.) Tali Forth 2 is hosted at 21 | GitHub. You can find the most current version at 22 | [https://github.com/SamCoVT/TaliForth2](https://github.com/SamCoVT/TaliForth2). 23 | 24 | 25 | ## A little more detail please 26 | 27 | Tali Forth 2 aims to be, roughly in order of priority: 28 | 29 | - **Easy to try.** Download the source -- or even just the binary 30 | `taliforth-py65mon.bin` -- and run the emulator with `py65mon -m 65c02 -r 31 | taliforth-py65mon.bin` to get it running. This lets you experiment with a 32 | working 8-bit Forth for the 65c02 without any special configuration. This 33 | includes things like block wordset. 34 | 35 | - **Simple**. The simple subroutine-threaded (STC) design and excessively 36 | commented source code give hobbyists the chance to study a working Forth at 37 | the lowest level. Separate documentation - including a manual with more than 38 | 100 pages - in the `docs` folder discusses specific topics and offers 39 | tutorials. The aim is to make it easy to port Tali Forth 2 to various 65c02 40 | hardware projects. 41 | 42 | - **Specific**. Many Forths available are "general" implementations with a small 43 | core adapted to the target processor. Tali Forth 2 was written as a "bare 44 | metal Forth" for the 65c02 8-bit MPU and that MPU only, with its strengths and 45 | limitations in mind. 46 | 47 | - **Standardized**. Most Forths available for the 65c02 are based on ancient, 48 | outdated templates such as FIG Forth. Learning Forth with them is like trying 49 | to learn modern English by reading Chaucer. Tali Forth (mostly) follows the 50 | current ANS Standard, and ensures this by passing an enhanced test suite. 51 | 52 | The functional reference for Tali is GNU Forth (Gforth, 53 | [https://www.gnu.org/software/gforth/](https://www.gnu.org/software/gforth/)). 54 | Programs written for Tali should run on Gforth or have a very good reason not 55 | to. Also, may Gforth words were adapted for Tali, especially when they make the 56 | code simpler (like `FIND-NAME` or `BOUNDS`). 57 | 58 | The first Tali Forth was my first Forth ever. It is hosted at 59 | [https://github.com/scotws/TaliForth](https://github.com/scotws/TaliForth) and 60 | is superceded by this version. The second version was strongly influenced by 61 | what I learned writing Liara Forth for the 65816. Liara and Tali 2 share large 62 | parts of their internal logic. 63 | 64 | 65 | ## Seriously super lots more detail 66 | 67 | See `docs\manual.html` for the Tali Forth manual, which covers the installation, 68 | setup, tutorials, and internal structure. The central discussion forum is 69 | [http://forum.6502.org/viewtopic.php?f=9&t=2926](http://forum.6502.org/viewtopic.php?f=9&t=2926) 70 | at 6502.org. 71 | -------------------------------------------------------------------------------- /c65/Makefile: -------------------------------------------------------------------------------- 1 | CCFLAGS=-Wall 2 | 3 | # Detect if running on native Windows: 4 | ifeq ($(OS),Windows_NT) 5 | CCFLAGS += -D WINDOWS_NATIVE 6 | endif 7 | 8 | CSRC = c65.c magicio.c monitor.c parse.c linenoise.c 9 | CHDR = $(patsubst %.c,%.h,$(CSRC)) fake65c02.h 10 | 11 | all: c65 tests 12 | 13 | c65: $(CSRC) $(CHDR) 14 | gcc $(CCFLAGS) $(CSRC) -o c65 15 | 16 | tests: c65 tests/test.in 17 | ./c65 -r tests/wozmon.rom -l tests/wozmon.sym < tests/test.in | perl -pe 's/\x1b\[[0-9;]*[mG]//g' > tests/test.out 18 | 19 | clean: 20 | rm -f *.o c65 c65.exe 21 | -------------------------------------------------------------------------------- /c65/TODO.md: -------------------------------------------------------------------------------- 1 | TODO 2 | 3 | - `continue ` would be useful to consume input and break on eof, e.g. for test coverage or 4 | batching an initial section of working code 5 | 6 | - option for case insensitive labels on load or always? 7 | 8 | - maybe restrict max dump / disasm size to 1K to avoid wraparound dump of almost all memory? 9 | 10 | - disassemble backward from PC would be handy but seems indeterminate, e.g. bytes $20 $80 $60 before 11 | PC could be JSR $6080, BRA $60 or RTS. can deduce where opcodes land if you have heatx data 12 | -------------------------------------------------------------------------------- /c65/c65.h: -------------------------------------------------------------------------------- 1 | /* access modes */ 2 | #define MONITOR_READ 1 3 | #define MONITOR_WRITE 2 4 | #define MONITOR_DATA (MONITOR_READ|MONITOR_WRITE) 5 | #define MONITOR_PC 4 6 | #define MONITOR_ANY (MONITOR_PC|MONITOR_DATA) 7 | #define MONITOR_ONCE 8 /* flag to clear on hit */ 8 | 9 | /* special break conditions */ 10 | #define MONITOR_BRK 16 /* BRK instruction */ 11 | #define MONITOR_SIGINT 32 /* break back to */ 12 | #define MONITOR_EXIT 64 /* exit simulation */ 13 | 14 | #define STEP_NONE 0 15 | #define STEP_INST 1 16 | #define STEP_NEXT 2 17 | #define STEP_OVER 3 18 | #define STEP_RUN 4 19 | 20 | extern uint8_t memory[0x10000]; 21 | extern uint8_t breakpoints[0x10000]; 22 | 23 | extern uint16_t pc; 24 | extern uint8_t a, x, y, sp, status; 25 | extern uint16_t rw_brk; 26 | 27 | extern uint64_t heat_rs[0x10000], heat_ws[0x10000], heat_xs[0x10000]; 28 | 29 | extern uint64_t ticks; 30 | extern int break_flag, step_mode, step_target; 31 | 32 | const char* opname(uint8_t op); 33 | uint8_t oplen(uint8_t op); 34 | const char* opfmt(uint8_t op); 35 | 36 | int get_reg_or_flag(const char *name); 37 | int set_reg_or_flag(const char *name, int v); 38 | 39 | int load_memory(const char* romfile, int addr); 40 | int save_memory(const char* romfile, uint16_t start, uint16_t end); 41 | 42 | extern void reset6502(); 43 | extern void irq6502(); 44 | extern void nmi6502(); -------------------------------------------------------------------------------- /c65/heatmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SamCoVT/TaliForth2/6c2bee7ddb5dcfb77d56c0bf92e0e9536fc1d86d/c65/heatmap.png -------------------------------------------------------------------------------- /c65/linenoise.h: -------------------------------------------------------------------------------- 1 | /* linenoise.h -- guerrilla line editing library against the idea that a 2 | * line editing lib needs to be 20,000 lines of C code. 3 | * 4 | * See linenoise.c for more information. 5 | * 6 | * ------------------------------------------------------------------------ 7 | * 8 | * Copyright (c) 2010, Salvatore Sanfilippo 9 | * Copyright (c) 2010, Pieter Noordhuis 10 | * 11 | * All rights reserved. 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are 15 | * met: 16 | * 17 | * * Redistributions of source code must retain the above copyright 18 | * notice, this list of conditions and the following disclaimer. 19 | * 20 | * * Redistributions in binary form must reproduce the above copyright 21 | * notice, this list of conditions and the following disclaimer in the 22 | * documentation and/or other materials provided with the distribution. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #ifndef __LINENOISE_H 38 | #define __LINENOISE_H 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | #ifndef NO_COMPLETION 45 | typedef struct linenoiseCompletions { 46 | size_t len; 47 | char **cvec; 48 | } linenoiseCompletions; 49 | 50 | /* 51 | * The callback type for tab completion handlers. 52 | */ 53 | typedef void(linenoiseCompletionCallback)(const char *prefix, linenoiseCompletions *comp, void *userdata); 54 | 55 | /* 56 | * Sets the current tab completion handler and returns the previous one, or NULL 57 | * if no prior one has been set. 58 | */ 59 | linenoiseCompletionCallback * linenoiseSetCompletionCallback(linenoiseCompletionCallback *comp, void *userdata); 60 | 61 | /* 62 | * Adds a copy of the given string to the given completion list. The copy is owned 63 | * by the linenoiseCompletions object. 64 | */ 65 | void linenoiseAddCompletion(linenoiseCompletions *comp, const char *str); 66 | 67 | typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold, void *userdata); 68 | typedef void(linenoiseFreeHintsCallback)(void *hint, void *userdata); 69 | void linenoiseSetHintsCallback(linenoiseHintsCallback *callback, void *userdata); 70 | void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *callback); 71 | 72 | #endif 73 | 74 | /* 75 | * Prompts for input using the given string as the input 76 | * prompt. Returns when the user has tapped ENTER or (on an empty 77 | * line) EOF (Ctrl-D on Unix, Ctrl-Z on Windows). Returns either 78 | * a copy of the entered string (for ENTER) or NULL (on EOF). The 79 | * caller owns the returned string and must eventually free() it. 80 | */ 81 | char *linenoise(const char *prompt); 82 | 83 | /** 84 | * Like linenoise() but starts with an initial buffer. 85 | */ 86 | char *linenoiseWithInitial(const char *prompt, const char *initial); 87 | 88 | /** 89 | * Clear the screen. 90 | */ 91 | void linenoiseClearScreen(void); 92 | 93 | /* 94 | * Adds a copy of the given line of the command history. 95 | */ 96 | int linenoiseHistoryAdd(const char *line); 97 | 98 | /* 99 | * Sets the maximum length of the command history, in lines. 100 | * If the history is currently longer, it will be trimmed, 101 | * retaining only the most recent entries. If len is 0 or less 102 | * then this function does nothing. 103 | */ 104 | int linenoiseHistorySetMaxLen(int len); 105 | 106 | /* 107 | * Returns the current maximum length of the history, in lines. 108 | */ 109 | int linenoiseHistoryGetMaxLen(void); 110 | 111 | /* 112 | * Saves the current contents of the history to the given file. 113 | * Returns 0 on success. 114 | */ 115 | int linenoiseHistorySave(const char *filename); 116 | 117 | /* 118 | * Replaces the current history with the contents 119 | * of the given file. Returns 0 on success. 120 | */ 121 | int linenoiseHistoryLoad(const char *filename); 122 | 123 | /* 124 | * Frees all history entries, clearing the history. 125 | */ 126 | void linenoiseHistoryFree(void); 127 | 128 | /* 129 | * Returns a pointer to the list of history entries, writing its 130 | * length to *len if len is not NULL. The memory is owned by linenoise 131 | * and must not be freed. 132 | */ 133 | char **linenoiseHistory(int *len); 134 | 135 | /* 136 | * Returns the number of display columns in the current terminal. 137 | */ 138 | int linenoiseColumns(void); 139 | 140 | /** 141 | * Enable or disable multiline mode (disabled by default) 142 | */ 143 | void linenoiseSetMultiLine(int enableml); 144 | 145 | #ifdef __cplusplus 146 | } 147 | #endif 148 | 149 | #endif /* __LINENOISE_H */ 150 | -------------------------------------------------------------------------------- /c65/magicio.c: -------------------------------------------------------------------------------- 1 | // PROGRAMMERS : Patrick Surry and Sam Colwell 2 | // FILE : io.c 3 | // DATE : 2024-05 4 | // DESCRIPTION : This abstracts the I/O and allows supporting multiple 5 | // environments (Linux, OSX, WSL, Native Windows) that all have gcc. 6 | #ifdef WINDOWS_NATIVE 7 | #include 8 | #include // Windows specific 9 | 10 | void set_terminal_nb() {} // No-op 11 | //int _kbhit(); // _kbhit already available in conio.h 12 | int _getc() { return getch(); } // getch() from conio.h has no echo. 13 | void _putc(char ch) { putchar(ch); fflush(stdout); return; } 14 | #else 15 | // These should work on Linux, OSX, and WSL. 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | struct termios orig_termios; 24 | 25 | void reset_terminal() { tcsetattr(0, TCSANOW, &orig_termios); } 26 | 27 | void set_terminal_nb() { 28 | struct termios new_termios; 29 | 30 | /* take two copies - one for now, one for later */ 31 | tcgetattr(0, &orig_termios); 32 | memcpy(&new_termios, &orig_termios, sizeof(new_termios)); 33 | 34 | /* register cleanup handler, and set the new terminal mode */ 35 | atexit(reset_terminal); 36 | 37 | /* see https://man7.org/linux/man-pages/man3/tcsetattr.3.html */ 38 | /* we want something close to cfmakeraw but we'll keep ONLCR and SIGINT etc */ 39 | new_termios.c_iflag &= ~(PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); 40 | new_termios.c_oflag |= OPOST | ONLCR; 41 | new_termios.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN); 42 | new_termios.c_cflag &= ~(CSIZE | PARENB); 43 | new_termios.c_cflag |= CS8; 44 | 45 | tcsetattr(0, TCSANOW, &new_termios); 46 | 47 | setbuf(stdout, NULL); /* unbuffered output */ 48 | } 49 | 50 | /* 51 | compatibility with windows _kbhit, return non-zero if key ready 52 | see https://stackoverflow.com/questions/448944/c-non-blocking-keyboard-input 53 | */ 54 | int _kbhit() { 55 | int flag; 56 | struct timeval tv = {0L, 0L}; 57 | fd_set fds; 58 | FD_ZERO(&fds); 59 | FD_SET(0, &fds); 60 | flag = select(1, &fds, NULL, NULL, &tv) > 0; 61 | if (!flag) usleep(1000); /* sleep 1ms to avoid busy loop */ 62 | return flag; 63 | } 64 | 65 | /* non-blocking version of getch() */ 66 | int _getc() { 67 | int r; 68 | unsigned char c; 69 | r = read(0, &c, sizeof(c)); 70 | return r < 0 ? r : c; 71 | } 72 | 73 | void _putc(char ch) { putchar((int)ch); } 74 | #endif 75 | 76 | #include 77 | #include 78 | #include "magicio.h" 79 | #include "c65.h" 80 | 81 | /* 82 | blkio supports the following action values. write the action value 83 | after setting other parameters to initiate the action. All actions 84 | return 0x0 on success and nonzero (typically 0xff) otherwise. 85 | A portable check for blkio is to write 0x1 to status, then write 0x0 to action 86 | and check if status is now 0. 87 | 0 - status: detect if blkio available, 0x0 if enabled, 0xff otherwise 88 | 1 - read: read the 1024 byte block @ blknum to bufptr 89 | 2 - write: write the 1024 byte block @ blknum from bufptr 90 | */ 91 | typedef struct BLKIO { 92 | uint8_t action; // I: request an action (write after setting other params) 93 | uint8_t status; // O: action status 94 | uint16_t blknum; // I: block to read or write 95 | uint16_t bufptr; // I/O: low-endian pointer to 1024 byte buffer to read/write 96 | } BLKIO; 97 | 98 | BLKIO *blkiop; 99 | FILE *fblk = NULL; 100 | int io_addr = 0xf000; 101 | long mark = 0; // used for timer 102 | 103 | #define io_putc (io_addr + 1) 104 | #define io_kbhit (io_addr + 3) 105 | #define io_getc (io_addr + 4) 106 | #define io_timer (io_addr + 6) 107 | #define io_blkio (io_addr + 16) 108 | 109 | 110 | void sigint_handler() { 111 | // catch ctrl-c and break back to monitor 112 | /*TODO in input loop still have to hit a key after ctrl-c */ 113 | break_flag |= MONITOR_SIGINT; 114 | } 115 | 116 | void io_init(int debug) { 117 | /* initialize blkio struct once io_addr is set */ 118 | blkiop = (BLKIO *)(memory + io_blkio); 119 | set_terminal_nb(); 120 | if (debug) signal(SIGINT, sigint_handler); 121 | } 122 | 123 | void io_exit() { 124 | io_blkfile(NULL); 125 | } 126 | 127 | 128 | FILE* io_blkfile(const char *fname) { 129 | if (fblk) fclose(fblk); 130 | if (fname) fblk = fopen(fname, "r+b"); 131 | return fblk; 132 | } 133 | 134 | 135 | void io_magic_read(uint16_t addr) { 136 | int ch; 137 | long delta; 138 | 139 | if (addr == io_kbhit) { 140 | memory[addr] = _kbhit() ? 0xff : 0; 141 | } else if (addr == io_getc) { 142 | ch = break_flag ? 0x03 : (_kbhit() ? _getc() : 0); 143 | if (ch == EOF) break_flag |= MONITOR_EXIT; 144 | memory[addr] = (uint8_t)ch; 145 | } else if (addr == io_timer /* start timer */) { 146 | mark = ticks; 147 | } else if (addr == io_timer + 1 /* stop timer */) { 148 | delta = ticks - mark; 149 | memory[io_timer + 2] = (uint8_t)((delta >> 16) & 0xff); 150 | memory[io_timer + 3] = (uint8_t)((delta >> 24) & 0xff); 151 | memory[io_timer + 4] = (uint8_t)((delta >> 0) & 0xff); 152 | memory[io_timer + 5] = (uint8_t)((delta >> 8) & 0xff); 153 | } 154 | } 155 | 156 | 157 | void io_magic_write(uint16_t addr, uint8_t val) { 158 | if (addr == io_putc) { 159 | _putc(val); 160 | } else if (addr == io_blkio) { 161 | blkiop->status = 0xff; 162 | if (fblk) { 163 | if (val < 3) { 164 | blkiop->status = 0; 165 | if (val == 1 || val == 2) { 166 | fseek(fblk, 1024 * blkiop->blknum, SEEK_SET); 167 | if (val == 1) { 168 | fread(memory + blkiop->bufptr, 1024, 1, fblk); 169 | } else { 170 | fwrite(memory + blkiop->bufptr, 1024, 1, fblk); 171 | fflush(fblk); 172 | } 173 | } 174 | } 175 | } 176 | } 177 | } 178 | 179 | -------------------------------------------------------------------------------- /c65/magicio.h: -------------------------------------------------------------------------------- 1 | extern int io_addr; 2 | 3 | void io_init(int debug); 4 | void io_exit(); 5 | 6 | FILE* io_blkfile(const char *fname); 7 | void io_magic_read(uint16_t addr); 8 | void io_magic_write(uint16_t addr, uint8_t); 9 | -------------------------------------------------------------------------------- /c65/monitor.h: -------------------------------------------------------------------------------- 1 | void monitor_init(const char *labelfile); 2 | void monitor_exit(); 3 | void monitor_command(); 4 | -------------------------------------------------------------------------------- /c65/parse.h: -------------------------------------------------------------------------------- 1 | /* 2 | Linked list of symbolic address labels. 3 | We can have multiple labels for a single address, 4 | but require that label names are unique. 5 | */ 6 | typedef struct Symbol { 7 | const char *name; 8 | uint16_t value; 9 | struct Symbol* next; 10 | } Symbol; 11 | 12 | extern const char *pexpr; 13 | 14 | void add_symbol(const char* name, uint16_t value); 15 | const Symbol* get_symbol(const char *name); 16 | const Symbol* get_next_symbol_by_value(const Symbol* sym, uint16_t value); 17 | void remove_symbol(const char *name); 18 | int remove_symbols_by_value(uint16_t value); 19 | 20 | #define DEFAULT_REQUIRED 0x10001 21 | #define DEFAULT_OPTIONAL 0x10002 22 | 23 | #define E_OK 0 24 | #define E_MISSING -1 25 | #define E_PARSE -2 26 | #define E_RANGE -3 27 | 28 | int strexpr(char *src, int *result); 29 | int symlen(const char *s); 30 | 31 | int parse_start(char *src); 32 | int parse_end(); 33 | char* parse_delim(); 34 | int parse_enum(const char *names[], const int vals[], uint8_t *v, int dflt); 35 | int parse_int(int *v, int dflt); 36 | int parse_byte(uint8_t *v, int dflt); 37 | int parse_addr(uint16_t *v, int dflt); 38 | int parse_range(uint16_t* start, uint16_t* end, int dflt_start, int dflt_length); 39 | 40 | char* parsed_str(); 41 | int parsed_length(); 42 | -------------------------------------------------------------------------------- /c65/tests/README.md: -------------------------------------------------------------------------------- 1 | These are basic tests of monitor functionality using a tiny wozmon image. 2 | 3 | Rebuild wozmon.rom and wozmon.sym if required: 4 | 5 | 64tass --nostart --vice-labels --labels=wozmon.sym --output wozmon.rom wozmon.asm 6 | 7 | Run the tests like: 8 | 9 | ./c65 -r tests/wozmon.rom -l tests/wozmon.sym < tests/test.in | perl -pe 's/\x1b\[[0-9;]*[mG]//g' > tests/test.out 10 | -------------------------------------------------------------------------------- /c65/tests/test.in: -------------------------------------------------------------------------------- 1 | ; a few simple tests based on wozmon rom 2 | quit extraneous ; trailing text warning 3 | disassemble 4 | DIS ; commands are case insensitve 5 | dis RESET . NOTCR 6 | d ESCAPE .. 6 7 | d escape .. 6 ; error: labels are case sensitive (and not $e .. 6) 8 | label alpha a000 9 | unl alpha 10 | label 6ty b000 ; invalid label 11 | set A 42 ; reserved labels are case insensitive 12 | set x 10 13 | set v 1 14 | set c false ; error, not C=$fa 15 | set c 1 16 | break PRBYTE + 1 17 | call PRBYTE 18 | step 19 | s 3 20 | next 21 | d 22 | b $100.1ff r ; break on any stack read 23 | inspect 24 | c 25 | stack 26 | ; test some simple expressions 27 | ~ 32 #50 1+3*2 (1+3)*2 28 | ~ (<(1 ? -1 : 2)) (<(0 ? 2 : -1)) 1234 & $ff 29 | ~ 3 < 4 3 > 4 3 < 3 3 <= 3 4 >= 3 30 | ~ RESET = 3 3==3 RESET <> 3 3!=3 31 | fill 400..f 12 34 32 | f 410 30 $31 '2 #51 %110100 35 33 | f ; error: empty fill 34 | mem 400 35 | mem 400..20 36 | mem 400 . 420 37 | mem . 440 38 | mem .. 20 39 | ; repeat empty command 40 | mem fffa..3 41 | mem fffa..20 42 | mem 43 | dis fffa ; check disassembly stops at end of memory 44 | dis fffa..5 45 | d fffa .. 10 46 | f 20 34 12 ; $20 contains byte 34, word 1234 47 | f 34 00 ff ; $34 contains word $ff00 48 | f 1234 1 2 3 4 49 | m *20 ; dereference zp byte 50 | label ptr 20 51 | m @ptr ; derefernce zp word (20 -> 1234) 52 | d @*ptr ; dereference indirect zp word (20 -> 34 -> $ff00) 53 | heat 54 | q 55 | -------------------------------------------------------------------------------- /c65/tests/wozmon.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SamCoVT/TaliForth2/6c2bee7ddb5dcfb77d56c0bf92e0e9536fc1d86d/c65/tests/wozmon.rom -------------------------------------------------------------------------------- /c65/tests/wozmon.sym: -------------------------------------------------------------------------------- 1 | al ffb1 .PRDATA 2 | al ffbb .XAMNEXT 3 | al ff8b .RUN 4 | al 2a .YSAV 5 | al 24 .XAML 6 | al ff35 .SETSTOR 7 | al 25 .XAMH 8 | al ffe6 .ECHO 9 | al ffdc .PRHEX 10 | al 200 .IN 11 | al ff76 .NOTHEX 12 | al ff10 .ESCAPE 13 | al ff1f .NEXTCHAR 14 | al ff9b .NXTPRNT 15 | al ffef .OUT 16 | al ff00 .RESET 17 | al ff05 .NOTCR 18 | al ffd3 .PRBYTE 19 | al ff88 .TONEXTITEM 20 | al ff6b .HEXSHIFT 21 | al ff54 .NEXTHEX 22 | al ff39 .NEXTITEM 23 | al 26 .STL 24 | al 29 .H 25 | al f004 .GETC 26 | al 27 .STH 27 | al 28 .L 28 | al ff38 .BLSKIP 29 | al ff1c .BACKSPACE 30 | al 2b .MODE 31 | al ff36 .SETMODE 32 | al ff92 .SETADR 33 | al f001 .PUTC 34 | al ff65 .DIG 35 | al ffcd .MOD8CHK 36 | al ff15 .GETLINE 37 | al ff8e .NOTSTOR 38 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Documentation for Tali Forth 2 2 | Scot W. Stevenson 3 | 4 | Tali Forth's documentation is written in AsciiDoc and compiled to other versions 5 | with the following commands: 6 | 7 | - HTML: `asciidoctor -a toc=left manual.adoc` 8 | - PDF: `asciidoctor-pdf -v manual.adoc` 9 | 10 | Converting to GitHub's markdown is tricker than you would think. There is an 11 | experimental script included in this folder, `asciidoc_to_markdown.sh`, that 12 | however eats the title line for some reason. This must be added by hand at 13 | the moment. See https://github.com/asciidoctor/asciidoctor/issues/1907 14 | 15 | Apart from that, this folder looks messier than it is -- what you are probably 16 | looking for are the `manual.html`, `manual.pdf` and possibly the `WORDLIST.md` 17 | files. There are also the listing files here generated by the Ophis assembler. 18 | -------------------------------------------------------------------------------- /docs/asciidoc_to_markdown.sh: -------------------------------------------------------------------------------- 1 | # Convert asciidoc to docbook using asciidoctor 2 | # Based on: https://github.com/asciidoctor/asciidoctor/issues/1907 3 | # by Dan Allen 4 | # This version Scot W. Stevenson 5 | # First version 08. Nov 2018 6 | # This version 08. Nov 2018 7 | asciidoctor -b docbook -a leveloffset=+1 -o - manual.adoc | pandoc --wrap=preserve -t gfm -f docbook - > manual.md 8 | 9 | # Known problems: The title line is eaten by pandoc, though the "leveloffset" 10 | # value is supposed to stop this 11 | -------------------------------------------------------------------------------- /docs/ch_bibliography.adoc: -------------------------------------------------------------------------------- 1 | * [[[FB]]] _Masterminds of Programming_, Federico Biancuzzi, 2 | O'Reilly Media 1st edition, 2009. 3 | 4 | * [[[CHM1]]] "Charles H. Moore: Geek of the Week", redgate Hub 2009 5 | https://www.red-gate.com/simple-talk/opinion/geek-of-the-week/chuck-moore-geek 6 | 7 | * [[[CHM2]]] "The Evolution of FORTH, an Unusual Language", Charles H. Moore, 8 | _Byte_ 1980, https://wiki.forth-ev.de/doku.php/projects:the_evolution_of_forth 9 | 10 | * [[[CnR]]] _Forth Programmer's Handbook_, Edward K. Conklin and Elizabeth Rather, 11 | 3rd edition 2010 12 | 13 | * [[[DB]]] _Forth Enzyclopedia_, Mitch Derick and Linda Baker, 14 | Mountain View Press 1982 15 | 16 | * [[[DH]]] "Some notes on Forth from a novice user", Douglas Hoffman, Feb 1988 17 | https://wiki.forth-ev.de/doku.php/projects:some_notes_on_forth_from_a_novice_user 18 | 19 | * [[[DMR]]] "Reflections on Software Research", Dennis M. Ritchie, Turing Award 20 | Lecture in _Communications of the ACM_ August 1984 Volume 27 Number 8 21 | http://www.valleytalk.org/wp-content/uploads/2011/10/p758-ritchie.pdf 22 | 23 | * [[[EnL]]] _Programming the 65816, including the 6502, 65C02 and 65802_, 24 | David Eyes and Ron Lichty 25 | (Currently not available from the WDC website) 26 | 27 | * [[[EW]]] "Forth: The Hacker's Language", Elliot Williams, 28 | https://hackaday.com/2017/01/27/forth-the-hackers-language/ 29 | 30 | * [[[GK]]] "Forth System Comparisons", Guy Kelly, in _Forth Dimensions_ V13N6, 31 | March/April 1992 32 | http://www.forth.org/fd/FD-V13N6.pdf}{http://www.forth.org/fd/FD-V13N6.pdf 33 | 34 | * [[[JVN]]] _A Beginner's Guide to Forth_, J.V. Nobel, 35 | http://galileo.phys.virginia.edu/classes/551.jvn.fall01/primer.htm 36 | 37 | * [[[BWK]]] _A Tutorial Introduction to the UNIX Text Editor_, B. W. Kernighan, 38 | http://www.psue.uni-hannover.de/wise2017_2018/material/ed.pdf 39 | 40 | * [[[LB1]]] _Starting Forth_, Leo Brodie, new edition 2003, 41 | https://www.forth.com/starting-forth/}{https://www.forth.com/starting-forth/ 42 | 43 | * [[[LB2]]] _Thinking Forth_, Leo Brodie, 1984, 44 | http://thinking-forth.sourceforge.net/\#21CENTURY 45 | 46 | * [[[LL]]] _6502 Assembly Language Programming_, Lance A. Leventhal, 47 | OSBORNE/McGRAW-HILL 1979 48 | 49 | * [[[PHS]]] "The Daemon, the Gnu and the Penguin", Peter H. Saulus, 22. April 2005, 50 | http://www.groklaw.net/article.php?story=20050422235450910 51 | -------------------------------------------------------------------------------- /docs/ch_blocks.adoc: -------------------------------------------------------------------------------- 1 | Tali supports the optional BLOCK word set. The 2012 Forth standard 2 | defines a block as 1024 bytes, and the buffers for them are the same 3 | size (as opposed to some older forths that had smaller buffers). Tali 4 | currently comes with one buffer. 5 | 6 | Before these words can be used, the user needs to write two routines: one for 7 | reading blocks into RAM and one for writing blocks out from RAM. Both of these 8 | should have the signature ( addr blk# -- ). Once these have been written, they 9 | can be incorporated into the BLOCK word set by changing the vectors for words 10 | `block-read` and `block-write`. That might look like: 11 | 12 | ---- 13 | ' myblockreader BLOCK-READ-VECTOR ! 14 | ' myblockwriter BLOCK-WRITE-VECTOR ! 15 | ---- 16 | 17 | These vectors determine what runs when the words `block-read` and 18 | `block-write` are used. Both of these words start with an error 19 | message asking you to update the vectors. Once these two vectors have 20 | been updated, you can use the block words. 21 | 22 | If you would like to play with some blocks, but don't have any 23 | hardware or are running Tali in a simulator, fear not! Tali has a 24 | built-in RAM drive that can be used on any hardware or simulator. If using the 25 | c65 simulator that comes with Tali, persistant storage can be simulated using 26 | a file on the PC. 27 | 28 | The following tutorial walks through some examples using -------------------------------------------------------------------------------- /docs/ch_disasm.adoc: -------------------------------------------------------------------------------- 1 | Tali Forth is currently shipped with a very primitive disassembler, which is 2 | started with `disasm ( addr u -- )`. 3 | 4 | === Format 5 | 6 | The output format is in Simpler Assembler Notation (SAN). Briefly, the 7 | instruction's mode is added to the mnemonic, leaving the operand a pure number. 8 | For use in a postfix environment like Tali Forth, the operand is listed _before_ 9 | the mnemonic. This way, traditional assembly code such as 10 | 11 | ---- 12 | LDA #1 13 | DEC 14 | STA $1000 15 | STA $80 16 | NOP 17 | LDA ($80) 18 | ---- 19 | 20 | becomes (assuming `hex` for hexadecimal numbers): 21 | 22 | ---- 23 | 1 lda.# 24 | dec.a 25 | 1000 sta 26 | 80 sta.z 27 | nop 28 | 80 lda.zi 29 | ---- 30 | 31 | See the Appendix for a more detailed discussion of the format. 32 | 33 | 34 | === Output 35 | 36 | The disassembler prints the address of the instruction, followed by any operand 37 | and the mnemonic. To get the code of `drop`, for instance, we can use 38 | `' drop 6 disasm`: 39 | 40 | ---- 41 | 36142 55337 jsr STACK DEPTH CHECK 42 | 36145 inx 43 | 36146 inx 44 | 36147 rts 45 | ---- 46 | 47 | The Forth word `see` calls the disassembler while using a hexadecimal number 48 | base. So `see drop` produces: 49 | 50 | ---- 51 | nt: BC34 xt: 8653 52 | flags: CO 0 IM 0 AN 0 NN 0 HC 0 | UF 1 ST 0 53 | size (decimal): 5 54 | 55 | 8653 20 B5 D8 E8 E8 .... 56 | 57 | 8653 D8B5 jsr 1 STACK DEPTH CHECK 58 | 8656 inx 59 | 8657 inx 60 | ---- 61 | 62 | Note that `see` does not print the final `rts` instruction. 63 | 64 | === Determining address labels 65 | 66 | When disassembling, using either `disasm` or `see`, the dictionary is searched 67 | anytime a `jsr` is encountered and the name of the word will be printed if a 68 | word with that address is found. Some interal routines in Tali are not in the 69 | Forth dictionary and so no name will be printed. Here is an example when running 70 | `see order` 71 | 72 | ---- 73 | nt: CA31 xt: B31A 74 | flags: CO 0 IM 0 AN 0 NN 0 HC 0 | UF 0 ST 0 75 | size (decimal): 42 76 | 77 | B31A 20 EC 83 20 EA B2 B5 00 F0 1E A8 E8 E8 B5 00 5A .. .... .......Z 78 | B32A 20 45 B3 7A 88 D0 F4 20 B3 91 20 B3 91 20 DF B2 E.z... .. .. .. 79 | B33A B5 00 20 45 B3 20 EC 83 E8 E8 .. E. .. .. 80 | 81 | B31A 83EC jsr cr 82 | B31D B2EA jsr get-order 83 | B320 0 lda.zx 84 | B322 1E beq B342 v 85 | B324 tay 86 | B325 inx 87 | B326 inx 88 | B327 0 lda.zx 89 | B329 phy 90 | B32A B345 jsr 91 | B32D ply 92 | B32E dey 93 | B32F F4 bne B325 ^ 94 | B331 91B3 jsr space 95 | B334 91B3 jsr space 96 | B337 B2DF jsr get-current 97 | B33A 0 lda.zx 98 | B33C B345 jsr 99 | B33F 83EC jsr cr 100 | B342 inx 101 | B343 inx 102 | ---- 103 | 104 | This word is a mixture of assembly and other forth words. Note that the second 105 | to last jsr shows a destination address of 9870 (in hex). To trace this 106 | further, consult the labelmap for your platform in the /docs folder. In this 107 | case, searching for 9870 in the labelmap finds the following label and the 108 | assembly files can be searched to locate this routine if you need to see its 109 | source. 110 | 111 | ---- 112 | order_print_wid_string= $9870 113 | ---- 114 | 115 | === Literals and Strings 116 | 117 | Tali compiles literals into words by saving a jsr to a helper 118 | routine followed immediately by the data for the literal. During 119 | disassembly, the literal value will be printed and the disassembler will resume 120 | disassembling from just after the literal value. Doubles are saved in memory as 121 | two single cell literal values. 122 | 123 | Strings are similar, they are saved in memory as a jsr to the string handling routine, 124 | then the string length and inline string data (similar to how literals are 125 | handled). When the disassembler encounters a string, it will print SLITERAL 126 | followed by the length of the string and a snippet of the data: 127 | ---- 128 | : example s" This is a string" ; ok 129 | see example 130 | nt: 827 xt: 836 131 | flags: CO 0 IM 0 AN 0 NN 0 HC 0 | UF 0 ST 0 132 | size (decimal): 21 133 | 134 | 0836 20 29 A2 10 00 54 68 69 73 20 69 73 20 61 20 73 )...Thi s is a s 135 | 0846 74 72 69 6E 67 tring 136 | 137 | 836 A229 jsr SLITERAL 10 This is a strin... 138 | ok 139 | ---- 140 | To see the value of the string, you can either look at the memory dump above the 141 | disassembly or you can `type` the string yourself (note that `see` will always 142 | give the values in hex while `disasm` will use the current `base`): 143 | ---- 144 | hex 836 5 + 10 cr type 145 | This is a string ok 146 | ---- 147 | 148 | === Gotchas and known issues 149 | 150 | Tali Forth enforces the *signature byte* of the `brk` assembler instruction. 151 | That is, it is treated like a two-byte instruction. Since you probably shouldn't be 152 | using `brk` anyway, this behavior is usually only interesting when examing the 153 | code, where a block of zeros will produce something like the following with the 154 | disassembler: 155 | 156 | ---- 157 | 124B 0 brk 158 | 124D 0 brk 159 | 124F 0 brk 160 | 1251 0 brk 161 | ---- 162 | 163 | Because of the stack structure of Forth, the disassembler will not catch 164 | assembler instructions that were *assigned an operand by mistake*. Take this 165 | (broken) code: 166 | 167 | ---- 168 | nop 169 | 10 dex <1> 170 | nop 171 | rts 172 | ---- 173 | <1> Error: DEX does not take an operand! 174 | 175 | The disassembler will output this code (addresses might vary): 176 | ---- 177 | 4661 nop 178 | 4662 dex <1> 179 | 4663 nop 180 | 4664 rts 181 | ---- 182 | <1> Incorrect operand for DEX was silently ignored 183 | 184 | The 10 we had passed as an operand are still on the stack, as `.s` will show. A 185 | `dump` of the code will show that the number was ignored, leading to code that 186 | will actually run correctly (again, addresses will vary): 187 | 188 | ---- 189 | 1235 EA CA EA 60 190 | ---- 191 | 192 | These mistakes can surface further downstream when the incorrect value on the 193 | Data Stack causes problems. 194 | 195 | -------------------------------------------------------------------------------- /docs/ch_editor_block.adoc: -------------------------------------------------------------------------------- 1 | If you are using blocks (see the block chapter), you can use the following words 2 | to enter text or Forth code. The built-in editor allows you to replace a 3 | single line or an entire screen. Screens are 16 lines (numbered 0-15) of 64 4 | characters each, for a total of 1K characters. Because newlines are not stored 5 | in the blocks (the remainder of each line is filled with spaces,) you should 6 | leave a space in the very last character of each line to separate the words in 7 | that line from the words in the next line. 8 | 9 | To get started, the editor words need to be added to the search order. To do 10 | that, you can just run: 11 | 12 | ---- 13 | editor-wordlist >order 14 | ---- 15 | 16 | To use the editor, first select a screen to work with by running `list` on it. If 17 | you are planning on using `load` to run some code later, it's worth noting that 18 | only screens above 0 can be LOADed. Screen 0 is reserved for comments describing 19 | what is on the other screens. It can be LISTed and edited, but cannot be 20 | LOADed. 21 | 22 | ---- 23 | 1 list 24 | ---- 25 | 26 | Tali will show you the current (blank) contents of that screen. 27 | 28 | ---- 29 | Screen # 1 30 | 0 31 | 1 32 | 2 33 | 3 34 | 4 35 | 5 36 | 6 37 | 7 38 | 8 39 | 9 40 | 10 41 | 11 42 | 12 43 | 13 44 | 14 45 | 15 46 | ok 47 | ---- 48 | 49 | To add some text to line 3, you might say 50 | 51 | ---- 52 | 3 o 53 | ---- 54 | 55 | This will give you a prompt to enter the text to overwrite line 3. 56 | You can enter up to 64 characters. Once you have selected a screen 57 | with `list`, you can use just `L` to list it again. 58 | 59 | To replace the contents of an entire screen, you can say something 60 | like: 61 | 62 | ---- 63 | 2 enter-screen 64 | ---- 65 | 66 | This will prompt you, line by line, for the new contents to screen 2. 67 | 68 | Once you have your screens the way you want them, you can type 69 | 70 | ---- 71 | flush 72 | ---- 73 | 74 | to flush your changes out to storage. 75 | 76 | You can enter Forth code on these screens. At the moment, Tali only 77 | supports comments in parentheses inside of blocks, so make sure you 78 | put your comments ( like this ) rather than using \ when entering 79 | Forth code. To load the Forth code on a screen, just type something 80 | like: 81 | 82 | ---- 83 | 2 load 84 | ---- 85 | 86 | Because a screen only holds 16 lines, you may need to split your code 87 | across multiple screens. You can load a series of screens (in order) 88 | using the `thru` command like so: 89 | 90 | ---- 91 | 1 3 thru 92 | ---- 93 | 94 | For more examples of the block editor being used, see the tutorials on working 95 | with blocks. -------------------------------------------------------------------------------- /docs/ch_editor_ed.adoc: -------------------------------------------------------------------------------- 1 | [quote, B. W. Kernighan, A Tutorial Introduction to the UNIX Text Editor] 2 | Ed makes no response to most commands – there is no prompting or typing of 3 | messages like "ready". (This silence is preferred by experienced users, but 4 | sometimes a hangup for beginners.) <> 5 | 6 | Tali Forth 2 currently ships with a clone of the `ed` line-based editor of Unix 7 | fame. It is envoked with `ed:`, though the formal name is `ed6502`. 8 | 9 | TIP: `ed:` uses about 2 KB of ROM in the default setup. If you know for certain 10 | you are not going to be using it, you can reclaim that space by removing "ed" 11 | from the TALI_OPTIONAL_WORDS list in your platform file. 12 | 13 | For those not familiar with UNIX `ed`, there is <> included 14 | in this manual. This section is a brief overview of the currently available 15 | functions. 16 | 17 | === Supported Commands 18 | 19 | `ed:` currently supports only a small number of the commands of the Unix version: 20 | 21 | [horizontal] 22 | a:: Add new lines below given line 23 | d:: Delete line 24 | f:: Show current target address for writes (`w`) 25 | i:: Add new lines above given line 26 | p:: Print lines 27 | n:: Print lines with line numbers 28 | q:: Quit if no unsaved work 29 | Q:: Unconditional quit, unsaved work is lost 30 | w:: Write text to given memory location (eg `7000w`) 31 | =:: Print value of given parameter (eg `$=` gives number of last line) 32 | 33 | The following parameters are currently available: 34 | 35 | [horizontal] 36 | .:: Current line number 37 | ,:: When alone: All lines, the same as `1,$` or `%` 38 | ;:: Range from current line to end, same as `.,$` 39 | $:: Last line 40 | %:: All lines, the same as `1,$` or `,` alone 41 | 42 | An empty line (pressing the ENTER key) will advance by one line and print it. A 43 | simple number will print that line without the line number and make that line 44 | the new current line. 45 | 46 | === Future planned commands 47 | 48 | These are subject to available memory. There is also no time frame for these 49 | additions. 50 | 51 | [horizontal] 52 | +:: Advance by one line, print it and make it the new current line 53 | -:: Go back by one line, print it and make it the new current line 54 | c:: Change a line, possibly adding new lines 55 | e:: Edit lines given as `addr,u` in text buffer 56 | j:: Join two lines to a new line 57 | m:: Move block of text to new line 58 | r:: Append text from a block to end of text buffer 59 | s:: Substitute one string on line with another 60 | !:: Execute a shell command (Forth command in our case) 61 | #:: Comment, ignore rest of the line 62 | 63 | === Differences to Unix ed 64 | 65 | Apart from missing about 90 percent of the features: 66 | 67 | - The `w` (write) command takes its parameter before and not after the word. 68 | Where Unix ed uses the format `w `, ed6502 takes the address 69 | to write the text to as `7000w`. 70 | 71 | WARNING: `ed:` currently only works with decimal numbers. It saves and 72 | restores BASE, but all numbers inside ed: will be decimal. This includes 73 | the address used with `w`. 74 | 75 | === Using `ed` for programming 76 | 77 | `Ed:` can be used to write programs and then execute them with `evaluate`. For 78 | instance, a session to add a small string could look something like this: 79 | 80 | ---- 81 | ed: 82 | a 83 | .( Shepard, is that ... You're alive?) 84 | . 85 | 7000w <1> 86 | 22 <2> 87 | q 88 | ---- 89 | <1> Address we save the command to 90 | <2> Number of characters saved including final line feed 91 | 92 | It is a common mistake to forget the `.` (dot) to end the input, and try to 93 | go immediately to saving the text. Then, we can run the program: 94 | 95 | ---- 96 | evaluate 97 | ---- 98 | 99 | Note that `evaluate` will handle line feeds, carriage returns and other white 100 | space apart from simple spaces without problems. 101 | 102 | === Known Issues 103 | 104 | ==== Memory use 105 | 106 | `Ed:` currently uses memory without releasing it when done. For small, quick 107 | edits, this probably is not a problem. However, if you known you are going to be 108 | using more memory, you probably will want to set a marker first. 109 | 110 | ---- 111 | marker pre-edit <1> 112 | ed: <2> 113 | pre-edit <3> 114 | ---- 115 | <1> Set marker at current value of `here` 116 | <2> Edit normally 117 | <3> Call marker, releasing memory 118 | 119 | This issue might be taken care of in a future release. 120 | 121 | ==== Address of Saved Text 122 | 123 | `Ed:` returns the address of the saved text on the stack as `( -- addr u )`. If 124 | nothing is saved, the program would return a zero length as TOS. 125 | 126 | === Developer Information 127 | 128 | The "buffer" of `ed:` is a simple single-linked list of nodes, consisting of a pointer 129 | to the next entry, a pointer to the string address, and the length of that 130 | string. 131 | 132 | image::pics/ed_node.png[] 133 | 134 | Each entry is two bytes, making six bytes in total for each node. A 135 | value of 0000 in the pointer to the next address signals the end of the list. 136 | The buffer starts at the point of the `cp` (accessed with the Forth word `here`) 137 | and is only saved to the given location when the `w` command is given. 138 | -------------------------------------------------------------------------------- /docs/ch_faq.adoc: -------------------------------------------------------------------------------- 1 | What happened to Tali Forth 1 anyway?:: 2 | Tali Forth 1(((Tali Forth 1))), informally just Tali Forth, was my first Forth. 3 | As such, it is fondly remembered as a learning experience. You can still find 4 | it online at GitHub(((GitHub))) at https://github.com/scotws/TaliForth. When 5 | Tali Forth 2 entered BETA, Tali Forth was discontinued. It does not 6 | receive bug fixes. In fact, new bugs are not even documented. 7 | 8 | [#img_talialpha] 9 | .Screenshot of the Tali Forth 1 boot screen, version Alpha 3, April 2014 10 | image::pics/tali_forth_alpha003.png[align=center] 11 | 12 | Who's "Tali"?:: 13 | I like the name, and we're probably not going to have any more kids I can give 14 | it to. If it sounds vaguely familiar, you're probably thinking of Tali'Zorah vas 15 | Normandy((("vas Normandy, Tali'Zorah"))) a character in the _Mass 16 | Effect_ (((Mass Effect))) universe created by BioWare(((BioWare))). This 17 | software has absolutely nothing to do with neither the game nor the companies and 18 | neither do I, expect that I've played the whole series and enjoyed it.footnote:[Though I do 19 | wish they would tell us what happened to the quarian ark in _Andromeda_.] 20 | 21 | And who is "Liara"?(((Liara Forth))):: 22 | Liara Forth is another STC Forth for the big sibling of the 6502, the 23 | 65816(((65816))). Tali Forth 1(((Tali Forth 1))) came first, then I wrote Liara 24 | with that knowledge and learned even more, and now Tali 2 is such much better 25 | for the experience. And yes, it's another _Mass Effect_ (((Mass Effect))) 26 | character. 27 | 28 | -------------------------------------------------------------------------------- /docs/ch_installing.adoc: -------------------------------------------------------------------------------- 1 | === Downloading 2 | 3 | Tali Forth 2 lives on GitHub(((GitHub))) at 4 | https://github.com/SamCoVT/TaliForth2. This is where you will always 5 | find the current version. You can either clone the code with 6 | git(((git))) or simply download it. To just test Tali Forth using the 7 | py65mon simulator, all you need is the binary file 8 | `taliforth-py65mon.bin`. 9 | 10 | === Running 11 | 12 | Tali currently supports two simulators, py65mon and c65. Py65mon will need to 13 | be downloaded separately (see below) and c65 comes with Tali in the c65 14 | folder. If you have `gcc` and `make` installed, you can just type (in the 15 | main Tali folder): 16 | 17 | [source,bash] 18 | ---- 19 | make csim 20 | ---- 21 | 22 | This will compile the c65 simulator (if it hasn't been compiled yet) and run 23 | Tali Forth 2 in the simulator. 24 | 25 | To exit, you can type `bye` or use CTRL-C to break out of the simulator. 26 | 27 | Note: If running on Windows in a git bash shell, you will need to use winpty, 28 | eg. `winpty make csim`. This is only needed for the git bash shell. Running 29 | Tali in c65 from the Windows command prompt or Windows Subsystem for Linux (WSL) 30 | works fine. 31 | 32 | ==== Downloading the py65mon Simulator 33 | 34 | Tali was written to run out of the box on the py65mon simulator from 35 | https://github.com/mnaberez/py65.(((py65mon))) This is a Python(((Python))) 36 | program that should run on various operating systems. 37 | 38 | To install py65mon on Linux(((Linux))), use one of the following commands 39 | 40 | [source,bash] 41 | ---- 42 | # Install for only your user: 43 | pip install -U py65 --user 44 | 45 | # Install for all users: 46 | sudo pip install -U py65 47 | ---- 48 | 49 | If you don't have `pip`(((pip))) installed, you will have to add it first with 50 | something like `sudo apt-get install python-pip` (Ubuntu Linux). Some systems 51 | use pip3 and you can run the above commands with pip3 instead of pip. 52 | 53 | If you are on windows, you will need to download and install Python 3 54 | first. Once Python is installed, the above commands should work from 55 | a Windows command prompt. 56 | 57 | 58 | ==== Running the Binary in py65mon 59 | 60 | To start Tali in the py65mon simulator, run: 61 | 62 | [source,bash] 63 | ---- 64 | py65mon -m 65c02 -r taliforth-py65mon.bin 65 | ---- 66 | 67 | Note that the option `-m 65c02` is required, because Tali Forth makes extensive 68 | use of the additional commands of the CMOS version and will not run on a stock 69 | 6502 MPU. 70 | 71 | If you downloaded the full Tali Forth 2 source code and have `make` 72 | installed, you can also just type: 73 | 74 | [source,bash] 75 | ---- 76 | make sim 77 | ---- 78 | 79 | to run Tali Forth 2 in the py65mon simulator (it will run the above 80 | command for you). 81 | 82 | === Installing on Your Own Hardware 83 | 84 | The Tali Forth project started out as a way to run Forth on my own 65c02 85 | computer, the Übersquirrel(((Übersquirrel))). Though it soon developed a life of 86 | its own, a central aim of the project is to provide a working, modern Forth that 87 | people can install on their projects. 88 | 89 | [#img_uebersquirrel] 90 | .The functioning Übersquirrel Mark Zero prototype, August 2013. Photo by Scot W. Stevenson 91 | image::pics/uebersquirrel.jpg[width=50%] 92 | 93 | ==== The Platform Files 94 | 95 | For this to work, you need to go to the `platform` folder and create your own 96 | kernel(((kernel))) code to replace `platform-py65mon.asm`, the default kernel 97 | for use with the py65mon(((py65mon))) kernel. By convention, the name should 98 | start with `platform-`. See the `README.md` file in the the `platform` folder 99 | for details. 100 | 101 | Once you have configured your platform file in the plaform folder, you 102 | can build a binary (typically programmed into an EEPROM) for your 103 | hardware with make. If you made a platform file named 104 | `platform-mycomp.asm`, then you should `cd` to the main Tali folder 105 | and run 106 | 107 | [source,bash] 108 | ---- 109 | make taliforth-mycomp.bin 110 | ---- 111 | 112 | The bin file will be created in the main folder. You should, of 113 | course, replace the "mycomp" portion of that command with whatever you 114 | named your platform. 115 | 116 | === Hardware Projects with Tali Forth 2 117 | 118 | This is a list of projects known to run Tali Forth 2. Please let me know if you 119 | want to have your project added to the list. 120 | 121 | - *Steckschwein* (https://steckschwein.de/) by Thomas Woinke and Marko 122 | Lauke. A multi-board 8 MHz 65c02 system. Platform file: 123 | `platform-steckschwein.asm` (26. Oct 2018) 124 | 125 | - *SamCo's SBC* (https://github.com/SamCoVT/SBC) by Sam Colwell. A 126 | single-board computer running at 4MHz. Platform file: 127 | `platform-sbc.asm` (29. Oct 2018) 128 | 129 | - *Neo6502* by Olimex LTD. A commercial offering that pairs a real 130 | 65C02 processor with an RP2040 to give HDMI output and USB keyboard 131 | support. Platform file: `platform-neo6502.asm` (28. Apr 2024) 132 | 133 | There are various benchmarks of Tali Forth 2 running different hardware at _The 134 | Ultimate Forth Benchmark_ (https://theultimatebenchmark.org/#sec-7). 135 | -------------------------------------------------------------------------------- /docs/ch_overview.adoc: -------------------------------------------------------------------------------- 1 | === Design Considerations 2 | 3 | When creating a new Forth, there are a bunch of design decisions to be 4 | made. 5 | 6 | NOTE: Probably the best introduction to these questions is found in "Design 7 | Decisions in the Forth Kernel" at 8 | http://www.bradrodriguez.com/papers/moving1.htm by Brad Rodriguez. 9 | 10 | Spoiler alert: Tali Forth is a subroutine-threaded (STC) variant with a 16-bit 11 | cell size and a dictionary that keeps headers and code separate. If you don't 12 | care and just want to use the program, skip ahead. 13 | 14 | ==== Characteristics of the 65c02 15 | 16 | Since this is a bare-metal Forth, the most important consideration is the target 17 | processor. The 65c02 only has one full register, the accumulator A, as well as 18 | two secondary registers X and Y. All are 8-bit wide. There are 256 bytes that 19 | are more easily addressable on the Zero Page. A single hardware stack is used 20 | for subroutine jumps. The address bus is 16 bits wide for a maximum of 64 KiB of 21 | RAM and ROM. 22 | 23 | For the default setup, we assume 32 KiB of each, but allow this to be changed so 24 | people can adapt Tali to their own hardware. 25 | 26 | ==== Cell Size 27 | 28 | The 16-bit address bus suggests the cell size should be 16 bits as well. This is 29 | still easy enough to realize on a 8-bit MPU. 30 | 31 | ==== Threading Technique 32 | 33 | A "thread" in Forth is simply a list of addresses of words to be executed. 34 | There are four basic threading techniques: <> 35 | 36 | Indirect threading (ITC):: The oldest, original variant, used by FIG Forth. All 37 | other versions are modifications of this model. 38 | 39 | Direct threading (DTC):: Includes more assembler code to speed things up, but 40 | slightly larger than ITC. 41 | 42 | Token threading (TTC):: The reverse of DTC in that it is slower, but uses less 43 | space than the other Forths. Words are created as a table of tokens. 44 | 45 | Subroutine threading (STC):: Converts the words to a simple 46 | series of `jsr` combinations. Easy to understand and less complex than the other 47 | variants, but uses more space and is slower. 48 | 49 | Our lack of registers and the goal of creating a simple and easy to understand 50 | Forth makes subroutine threading the most attractive solution, so Tali 2 is an 51 | STC Forth. We try to mitigate the pain caused by the 12 cycle cost of each and 52 | every `jsr`-`rts` combination by including a relatively high number of native 53 | words. 54 | 55 | 56 | ==== Register Use 57 | 58 | The lack of registers -- and any registers larger than 8 bit at that -- becomes 59 | apparent when you realize that Forth classically uses at least four virtual 60 | registers: 61 | 62 | .The classic Forth registers 63 | [%autowidth] 64 | |=== 65 | | Register | Name 66 | 67 | | W | Working Register 68 | | IP | Interpreter Pointer 69 | | DSP | Data Stack Pointer 70 | | RSP | Return Stack Pointer 71 | 72 | |=== 73 | 74 | On a modern processor like a RISC-V RV32I with 32 registers of 32 bit each, none 75 | of this would be a problem (in fact, we'd probably run out of ways to use the 76 | registers). On the 65c02, at least we get the RSP for free with the built-in 77 | stack pointer. This still leaves three registers. We cut that number down by one 78 | through subroutine threading, which gets rid of the IP. For the DSP, we use the 79 | 65c02's Zero Page indirect addressing mode with the X register. This leaves W, 80 | which we put on the Zero Page as well. 81 | 82 | 83 | ==== Data Stack Design 84 | 85 | We'll go into greater detail on how the Data Stack works in a later chapter 86 | when we look at the internals. Briefly, the stack is realized on the Zero Page 87 | for speed. For stability, we provide underflow checks in the relevant words, but 88 | give the user the option of stripping it out for native compilation. There are 89 | no checks for overflow because those cases tend to be rare. 90 | 91 | 92 | ==== Dictionary Structure 93 | 94 | Each Forth word consists of the actual code and the header that holds the 95 | meta-data. The headers are arranged as a simple single-linked list. 96 | 97 | In contrast to Tali Forth 1, which kept the header and body of the words 98 | together, Tali Forth 2 keeps them separate. This lets us play various tricks 99 | with the code to make it more effective. 100 | 101 | === Deeper down the rabbit hole 102 | 103 | This concludes our overview of the basic Tali Forth 2 structure. For those 104 | interested, a later chapter will provide far more detail. 105 | -------------------------------------------------------------------------------- /docs/ch_san.adoc: -------------------------------------------------------------------------------- 1 | 2 | NOTE: This is a condensed version of the main SAN Guide at 3 | https://github.com/scotws/SAN , see there for more detail.) 4 | 5 | === Background 6 | 7 | The Simpler Assembler Notation (SAN) for the 6502/65c02/65816 family of CPUs 8 | cleanly separates the opcode and the operand in an assembler instruction. For 9 | instance, the traditional notation 10 | 11 | ---- 12 | STA 1000,X 13 | ---- 14 | 15 | adds the marker for the X-indexed mode to the operand. Though this is not hard 16 | to read or use for the programmer on the 65c02, it makes building asssemblers 17 | and disassemblers harder. SAN keeps the mnemonic's "stem" - `STA` in this case - 18 | though it is converted to lower case. The mode is added as a "suffix" after a 19 | single dot: 20 | 21 | ---- 22 | sta.x 1000 23 | ---- 24 | 25 | In a Forth environment, this lets us trivially switch the notation to 26 | postfix. The operand is pushed to the stack like any normal number, and the 27 | mnemonic is a simple Forth word that picks it up there. 28 | 29 | ---- 30 | 1000 sta.x 31 | ---- 32 | 33 | As part of SAN, Zero Page modes are explicitly indicated with a `z` in the 34 | suffix. This removes any confusion that can come from 35 | 36 | ---- 37 | STA 10 ; zero page addressing, two-byte instruction 38 | STA 0010 ; absolut addressing, three-byte instruction 39 | STA 010 ; really not sure what will happen 40 | ---- 41 | 42 | by replacing the instruction with (prefix notation): 43 | 44 | ---- 45 | sta 10 ; absolute addressing, three-byte instruction 46 | sta.z 10 ; zero page addressing, two-byte instruction 47 | ---- 48 | 49 | SAN was originally invented to fix various issues with the traditional mnemonics 50 | for the 65816. The advantages for the 65c02 outside a specialized environment 51 | such as a small Forth assembler here are limited at best. 52 | 53 | === Complete list of 65c02 addressing modes 54 | 55 | |=== 56 | |Mode | Traditional Notation | SAN (Forth Postfix) 57 | 58 | |Implied | `DEX` | `dex` 59 | |Absolute | `LDA $1000` | `1000 lda` 60 | |Accumulator | `INC A` | `inc.a` 61 | |Immediate | `LDA #$00` | `00 lda.#` 62 | |Absolute X indexed | `LDA $1000,X` | `1000 lda.x` 63 | |Absolute Y indexed | `LDA $1000,Y` | `1000 lda.y` 64 | |Absolute indirect | `JMP ($1000)` | `1000 jmp.i` 65 | |Indexed indirect | `JMP ($1000,X)` | `1000 jmp.xi` 66 | |Zero Page (DP) | `LDA $10` | `10 lda.z` 67 | |Zero Page X indexed | `LDA $10,X` | `10 lda.zx` 68 | |Zero Page Y indexed | `LDX $10,Y` | `10 ldx.zy`` 69 | |Zero Page indirect | `LDA ($10)` | `10 lda.zi` 70 | |ZP indirect X indexed | `LDA ($10,X)` | `10 lda.zxi` 71 | |ZP indirect Y indexed | `LDA ($10),Y` | `10 lda.ziy` 72 | |Relative | `BRA