Jump to content

Search the Community

Showing results for tags 'forth'.

More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


  • Atari Systems
    • Atari General
    • Atari 2600
    • Atari 5200
    • Atari 7800
    • Atari Lynx
    • Atari Jaguar
    • Atari VCS
    • Dedicated Systems
    • Atari 8-Bit Computers
    • Atari ST/TT/Falcon Computers
  • Classic Consoles
  • Classic Computing
  • Modern Consoles
  • Gaming General
  • Marketplace
  • Community
  • Community
  • Game Programming
  • Site
  • PC Gaming
  • The Club of Clubs's Discussion
  • I Hate Sauron's Topics
  • 1088 XEL/XLD Owners and Builders's Topics
  • Atari BBS Gurus's Community Chat
  • Atari BBS Gurus's BBS Callers
  • Atari BBS Gurus's BBS SysOps
  • Atari BBS Gurus's Resources
  • Atari Lynx Programmer Club's CC65
  • Atari Lynx Programmer Club's ASM
  • Atari Lynx Programmer Club's Lynx Programming
  • Atari Lynx Programmer Club's Music/Sound
  • Atari Lynx Programmer Club's Graphics
  • The Official AtariAge Shitpost Club's Shitty meme repository
  • The Official AtariAge Shitpost Club's Read this before you enter too deep
  • Arcade Gaming's Discussion
  • Tesla's Vehicles
  • Tesla's Solar
  • Tesla's PowerWall
  • Tesla's General
  • Harmony/Melody's CDFJ
  • Harmony/Melody's DPC+
  • Harmony/Melody's BUS
  • Harmony/Melody's General
  • ZeroPage Homebrew's Discussion
  • Furry Club's Chat/RP
  • PSPMinis.com's General PSP Minis Discussion and Questions
  • PSPMinis.com's Reviews
  • Atari Lynx 30th Birthday's 30th Birthday Programming Competition Games
  • 3D Printing Club's Chat
  • Drivers' Club's Members' Vehicles
  • Drivers' Club's Drives & Events
  • Drivers' Club's Wrenching
  • Drivers' Club's Found in the Wild
  • Drivers' Club's General Discussion
  • Dirtarians's General Discussion
  • Dirtarians's Members' Rigs
  • Dirtarians's Trail Runs & Reports
  • Dirtarians's Wrenching
  • The Green Herb's Discussions
  • Robin Gravel's new blog's My blog
  • Robin Gravel's new blog's Games released
  • Atari Video Club's Harmony Games
  • Atari Video Club's The Atari Gamer
  • Atari Video Club's Video Game Summit
  • Atari Video Club's Discsuuions
  • Star Wars - The Original Trilogy's Star Wars Talk
  • PlusCart User's Bug reports
  • PlusCart User's Discussion
  • DMGD Club's Incoming!
  • DASM's General
  • AtariVox's Topics
  • Gran Turismo's Gran Turismo
  • Gran Turismo's Misc.
  • Gran Turismo's Announcements
  • The Food Club's Food
  • The Food Club's Drinks
  • The Food Club's Read me first!
  • The (Not So) Official Arcade Archives Club's Rules (READ FIRST)
  • The (Not So) Official Arcade Archives Club's Feedback
  • The (Not So) Official Arcade Archives Club's Rumor Mill
  • The (Not So) Official Arcade Archives Club's Coming Soon
  • The (Not So) Official Arcade Archives Club's General Talk
  • The (Not So) Official Arcade Archives Club's High Score Arena
  • Adelaide South Australia Atari Chat's General Chat & Welcome
  • Adelaide South Australia Atari Chat's Meets
  • Adelaide South Australia Atari Chat's Trades & Swaps
  • KC-ACE Reboot's KC-ACE Reboot Forum
  • The Official Lost Gaming Club's Lost Gaming
  • The Official Lost Gaming Club's Undumped Games
  • The Official Lost Gaming Club's Tip Of My Tounge
  • The Official Lost Gaming Club's Lost Gaming Vault
  • The Official Lost Gaming Club's Club Info
  • GIMP Users's Discussion


There are no results to display.

There are no results to display.


  • AtariAge Calendar
  • The Club of Clubs's Events
  • Atari BBS Gurus's Calendar

Find results in...

Find results that contain...

Date Created

  • Start


Last Updated

  • Start


Filter by number of...


  • Start










Custom Status



Currently Playing

Playing Next

Found 17 results

  1. This thread is a discussion of the evolution of fbForth, my file-based implementation of TI Forth. Though I have replaced the sector-based block I/O of TI Forth with a file-based version for fbForth, I have written utilities to browse TI Forth disks and to copy TI Forth blocks to fbForth blocks files (see latest FBLOCKS file far below). Several obvious advantages to using file I/O over sector I/O: It is simple to make a system disk of any larger size and density by just copying the system files to the new (usually larger) disk. If there is filespace on the system disk, you can save other useful programs there, such as CorComp's Disk Manager, without fear of corrupting the system disk. There is no danger of corrupting a disk by saving Forth blocks---they are only stored to the current blocks file. One can use disks of different sizes with impunity. The only significant disadvantage I can think of is not being able to use the new system with the old. The viewer/copier utilities, which I mentioned above and included in the latest FBLOCKS file posted far below, render that merely an inconvenience. There is also a slight performance penalty to reading 8 records one at a time instead of 4 sectors all at once for each block read. This is somewhat mitigated by saving 896 bytes of VRAM. I am certainly open to any and all suggestions. ...lee ---------------------------------------------------------------------- fbForth 2.0: A File-Based Cartridge Implementation of TI Forth is now published as a book available for $14.99 on Amazon.com. It is also on Amazon Europe for various similar prices: fbForth now has a website of its own: fbforth.stewkitt.com fbForth downloads & cartridge (fbForth 2.0)— fbForth 1.0 (E/A3 executable): Executable and FBLOCKS—fbForth100b.zip Manual—fbForth_1.0_Manual_a.pdf fbForth 2.0:13 (32KB ROM cartridge) [NOTE: Contains new Font Editor]: COINC and COINCXY now compare Δx and Δy to tolerance tol instead of comparing Δx2+Δy2 to 2tol2. No longer any trailing terminator bits in name fields in the dictionary—only using leading terminator bits Can now handle SAMS memory other than 1 MiB can be 128 KiB – 32 MiB SAMS? now reports highest addressable 4 KiB bank or 0 if not present 80-Column option on TI-startup screen. Bug fixes and the handful of words added to the resident dictionary are listed in posts #1067, #1116, #1170, #1173, #1426 and #1441 among others. The following additional words have also been added to the resident dictionary: BYE SD0 CMOVE> ABORT" DATA[ ]DATA DCHAR SPDCHAR CODE: ;CODE WRAP PANEL SCROLL TALKING? SAY STREAM SOUND PLAY PLAYING? S0&TIB! SAMS? SAMS! >MAP \ N>S DOES>CODE: S|F SM/REM FM/MOD ■■■CARTRIDGE available■■■ ($30 + S&H)—available at ArcadeShopper.com or PM me if you want me to build you one. fbForth 2.0 labels (as on the above cartridge image) at $0.50 each + S&H (1st class stamp)—PM me if interested. Four 8KiB Inverted Bank Binaries + Batch File (packs binaries, inverted or normal, into 32KiB, 64KiB, 128KiB, 256KiB and 512KiB images)— fbForth 2.0:13 BIN Packing Utility—fbForthBinPack_20210223.zip Classic99 & Real Iron 32KiB Inverted Binary (contains latest FBLOCKS and fbForthBinPack ZIPs) [ NOTE: In Classic99.ini, the rom0 line should be: rom0=9|0000|8000|MODS\fbForth200_9.bin for inverted banks and rom0=8|0000|8000|MODS\fbForth200_8.bin for normal (non-inverted) banks]— fbForth 2.0:13 for Classic99, EPROM burning, FlashROM99, FinalGROM99—fbForth200_20210223.zip MAME 32KiB Inverted Binary in RPK file (contains latest FBLOCKS and fbForthBinPack ZIPs)— fbForth 2.0:13 with RPK for MAME—fbForth200_MAME_20210223.zip Manual—fbForth 2.0: A File-Based Cartridge Implementation of TI Forth— [August 18, 2017 Book Publication]—See top of post for more information [April 28, 2017 Update]—fbForth_2.0_Manual_20170428.pdf Latest FBLOCKS file—(FIAD file; 90KiB, 360KiB and 400KiB (CF7+/nanoPEB) images; as well as a few font files)—FBLOCKS_20210223.zip, which includes Added UDSQRT—Unsigned 16-bit square root of an unsigned double number Fixed a bug in DIR Fixed a bug in the Floating Point Library that interfered with calculation of trigonometric functions Fixed a bug with DOT in Bitmap mode that ignored half of the possible colors for DCOLOR CFPMOUNT—This addition to the Compact Flash Utilities persists the mounted volume even after system reset Block #1 (Welcome Screen) modifications: Allows changing text colors to White on Blue Displays SAMS availability Bytes of free Low Memory (Return Stack grows down in this space from R0 ) Bytes of free High Memory (Dictionary grows up from HERE ; Stack grows down from S0) BLK>FILE—Current Blocks File to DV80 File export utility—ported from TurboForth with permission from Mark Wills FILE>BLK—DV80 File to Current Blocks File import utility—ported from TurboForth with permission from Mark Wills Compact Flash Utilities—Allow mounting of CF virtual disks in nanoPEB/CF7+ devices CF?—Leaves TRUE flag if CF&+/nanoPEB present; FALSE otherwise CFVOLS—Leaves volume #s associated with DSK1, DSK2 and DSK3 CFMOUNT—Temporarily (until system reset) mounts a volume in DSK1, DSK2 or DSK3 ASM>CODE—Outputs Machine Code in CODE: ... ;CODE format to a file in Append mode CPYBLK—Block Copying Utility—[fixed bug that would copy blocks from wrong file if they were already in block buffers and had corresponding block numbers] CRU Words—rewritten with CODE: ... ;CODE 64-Column Editor Memory Dump Utility [Note: VLIST is now part of the resident dictionary] TRACE—Colon Definition Tracing Printing Routines TMS9900 Assembler Disk Catalog Utility, DIR (ported from TurboForth code with @Willsy’s permission Disk Catalog Utility, CAT (reads VIB, FDIR and FDRs to extract information) More Useful Stack Words etc. (most required by the String Library) Portable String Library (ported by @Willsy and slightly modified by Yours Truly) TI Forth Block Utilities (includes a windowed viewer/copier)—fixed EMIT8 bug Compact Flash Utilities for mounting virtual disks in the nanoPEB/CF7+ In addition to the above, there are much-faster-loading binary images of the 64-Column Editor TMS9900 Assembler Portable String Library Note: The binary images in 4 menu options will only work with the revision of fbForth with which they were BSAVEd. The current revision is fbForth 2.0:13 and will work with the binary images in FBLOCKS_20210223.zip and later (until the next revision).
  2. Don't forget to visit Ninerpedia; our wiki about the TI-99/4A. Check here. If you are the owner of one of the programs or sites and do not want it posted, please let me know and it will be removed immediately. Also if you think a reference to an important development resource is missing, then please let me know and I'll be happy to add to the list. If you are new to the TI-99/4A or returning after a long time, then you might want to check out the TI-FAQ page here. Also make sure to visit the TI-99/4A Home Computer Book Archive by @airernie, now hosted by @acadiel. It's a great collection of excellent technical books about programming the TI-99/4A. Latest update: July 8th 2021 1. Emulators classic99 win Windows-based emulator including TI-99 ROMs under license from Texas Instruments. Debugger, memory heatmap, OS file support, support for 128K bank-switch carts, can create ROM/GROM cartridges, possibility to record AVI movies. User manual is included. Check the classic99 Updates thead for the latest news on classic99. Click here to watch Tursi's classic99 tips and tricks video tutorial. (Author: @Tursi) MAME win+linux Multiple system emulator that supports the TI-99/4, TI-99/4A, TI-99/8, and Geneve. Emulates more than 400 systems. Requires ROMs from the original systems. Features a powerful Debugger, most accurate emulation, support for 64K bank-switch carts / Gram Kracker / UCSD p-code expansion card. Possibility to record AVI movies. Also see the MAME section in ninerpedia. (Author: @mizapf) Js99'er All major browsers TI-99/4A emulator written in javascript. Has support for TMS9918A VDP & supports most of the F18A functionality, TMS9919 sound. Virtual disk drives using google drive. Some preloaded games, demos and applications included. Js99'er development thread on Atariage can be found here. Js99'er source code repository on Github can be found here. (Author: @Asmusr) V9t9 win+linux TI-99/4A emulator written in java. Has support for TMS9918A VDP, TMS9919 sound & TMS5220 speech. Debugger included. V9t9 also supports the UCSD P-Code system. Some of the advanced V9t9 features include: ability to save/restore emulator state, record & playback, support for V9938 VDP. Requires ROMs from the original systems. This emulator needs the Java Runtime Environment available for free at Oracle. V9t9 discussion thread can be found here. (Author: @eswartz) Win994a win Windows-based emulator of the TI-99/4a Good TMS9900 cross-assembler included. No debugger. Ti994w win Windows based emulator. Offers 80 column support, SAMS card 1Mb of RAM, V9938 support, built-in debugger, ... (Author: @F.G. Kaal) TI-99/Sim linux Linux-based software simulation of the TI-99/4A. PC99 DOS Commercial DOS-based emulator licensed by Texas Instruments to sell ROMs. 2. Programming languages Assembly language - Software Winasm99 win Windows based TMS9900 cross assembler with GUI and ability to build 8K cartridge roms. Is part of the Win994a emulator. asm990 linux Linux based cross Assembler for the TI 990 by Dave Pitts. You'll also need lnk990 a separate linker which can be found on the same page. TIasm win TMS9900 cross assembler TIasm will build 8K console (>0000) or cartridge (>6000) rom. Is part of the old V9T9 emulator package. Source is included. Editor/Assembler IV TI-99/4A Editor/Assembler IV is a module for the TI99/4A home computer. The software this cartridge contains is the in TMS9900 assembler rewritten Editor and Assembler loader, Program loader and an implementation of my own written Linking Loader and a simple debugger. The editor and debugger are running completely in the module space (>6000 - >7FFF). The assembler is copied from EPROM to CPU RAM before it is started. (Author: @F.G. Kaal) XA99 - Cross Assembler 99 win XA99 (Cross Assembler 99) is a program for assembling TMS9900 assembler code on the PC. (Author: @F.G. Kaal) L99 - Linker 99 win L99 is a tagged object file linker by Fred Kaal for creating program files for the TI99 and Geneve home computer. (Author: @F.G. Kaal) xdt99 - TI 99 Cross-Development Tools win, linux, OS X The TI 99 Cross-Development Tools (xdt99) are a small suite of programs that facilitate the development of programs for the TI 99 family of home computers on modern computer systems. All programs are written in Python and thus run on any platform that Python supports, including Linux, Windows, and Mac OS X. Includes xas99 (TMS9900 cross-assembler), xga99 (GPL cross-assembler!) and some command line tools for handling disk images and nanoPEB/CF7A+ volumes. The development thread on atariage can be found here. (Author: @ralphb) Assembly language - Manuals Editor/Assembler reference manual PDF The official Editor/Assembler reference manual. Note that this is not a tutorial for beginners. Still, it's an essential manual when writing assembler for the TI-99/4A. The online version can be found here. COMPUTE!'s beginner's guide to assembly language on the TI-99/4A PDF The Lottrup book. The only manual available today focusing on programming games in TMS9900 assembler. The examples in the book are for the Mini Memory line-by-line assembler which is rather limited. The manual also contains a few errors. Check here for the corrections. Nonetheless this book is a must-read for everyone seriously interested in writing assembler games for the TI-99/4A. The online version can be found here. Introduction to Assembly Language for the TI Home Computer PDF The Molesworth assembly language introduction book. Covers VDP communication, keyboard reading, file access and a lot more. The Art of Assembly series PDF The full series of articles by the late Bruce Harrison compiled as PDF. Over 600 pages, very well written and thorough. Assembly on the 99/4A WEB Excellent thread on Assembly language programming for the TI-99/4A, focussing on game loops, etc. (Author: @matthew180) SPECTRA2 zip Library for programming games in TMS9900 assembly language. Has routines for handling tiles, sprites, sound & task scheduler. Documentation manual PDF is included. (Author: @retroclouds) BASIC - Software Power BASIC TI-99/4A This is a port of the 'Power BASIC' interpreter used with the TMS9995-based Powertran Cortex machine. It is written in pure assembly. Graphic commands, sprites and saving to disk are supported. Currently no sound and speech supported. Power BASIC instruction manual available. Playground TI-99/4A Playground is a package making it possible to create assembly language programs that run from TI BASIC on an unexpanded console using only a cassette player to load the program(!) Although primarily intended for use in TI BASIC, programs written for playground can be run from XB, saved in E/A 5 format, loaded into a supercart, and even made into an actual cartridge. The manual describes in detail the differences in style necessary when programming for an environment that runs in only 256 bytes of memory. There is a library of subroutines for printing text, printing a number, shifting blocks in VDP, generating random numbers, using the line editor from BASIC, HCHAR, VCHAR,GPLLNK, a bit reversal routine, and a fast scroll routine. Source code is included for three different programs that should help you get started. Check here for the development thread on Atariage. Check this related thread for some clever work based on Playground. (Author: @senior_falcon) Extended BASIC - Software Extended Basic Game Developers Package "ISABELLA" TI-99/4A This package has been extensively updated to be faster, more versatile, and much simpler to use. It consists of two applications that make it possible to produce arcade quality games with XB. Although they are designed to complement each other, each is a stand alone utility. This is meant to be used with the Classic99 emulator, but the resulting programs are fully compatible with a real TI99 with nothing more than XB, 32K and a disk drive. Note that the included XBGDP package has an option to use the older TI BASIC only runtime routines if desired. It replaces for the older "Harry Wilhelm's BASIC COMPILER" and as a bonus, it's much easier and faster to use. (Author: @senior_falcon) 1) XB256 XB256 lets you toggle between two independent screens as desired. Screen2 lets you define all 256 characters and have up to 28 double sized sprites using the character definitions available to Screen1. Scrolling routines let you scroll characters left, right, up, or down or scroll using single pixels. There is a text crawl that gives an effect similar to the STAR WARS title screen. You can highlight text, set the sprite early clock, print in any direction on the screen using 32 columns, read/write to VDP ram, write compressed strings or sound tables to VDP ram, play a sound list, and catalog a disk. A utility lets you save selected areas of VDP memory as compressed strings that cn be merged with your program. With this, character definitions, sound tables, screen images, etc. can be saved in a more compact form that can be loaded virtually instantaneously, even in XB There are two utilities that convert the CALL SOUNDs in an XB program into a sound table containing music and sound effects. Sound tables can be loaded directly into VDP memory and played automatically while your XB program does other things. Also, a second player can play a different sound list simultaneously with the first, so you can have backgroundmusic playing and add sound effects on top of the background music. 2) XB COMPILER COMPILER lets you compile an XB program into an equivalent assembly language program that will run about 30 times faster. All the XB256 subprograms are supported by the compiler and in general, all the major features of XB are supported, including XB style IF/THEN/ELSE and named subprograms. About the only XB features that are not supported are DEF and the trig functions. T80XB TI-99/4A T80XB is a collection of assembly language subroutines that give the Extended BASIC programmer easy access to the 80 column screen mode offered by the F18A and other 80 column upgrades. Lets you select from two independent screens. G32 is the default screen when a program starts running.. This is the 32 column graphics mode screen normally used by Extended BASIC. It is accessed using the usual XB graphics statements. T80 is the 80 column text screen which offers 24 rows of 80 columns.. You can toggle between the two screens as desired, preserving the graphics on each screen. When using the T80 screen there are assembly equivalents that replace PRINT, CLEAR, COLOR, INPUT, CHAR, HCHAR, VCHAR plus routines that will scroll the screen and invert text on the screen. (Author: @senior_falcon) RXB 2020E TI-99/4A Rich Extended Basic (RXB) 2020E is an updated version of TI Extended Basic. Most bugs in XB have been fixed in RXB and GKXB is in the main core of RXB. RXB has features no other XB has such as batch processing, SAMS support, hard drive access or updated CALL routines. The below RXB tutorials on Youtube give a good overview of RXB's power: RXB DEMO 1 video RXB DEMO 2 video RXB DEMO 3 video RXB DEMO 4 video RXB DEMO 5 video RXB DEMO 6 video RXB DEMO 7 video RXB DEMO 8 video RXB DEMO 9 video RXB DEMO A video RXB DEMO B video RXB DEMO C video RXB 2020 Release video on features video RXB memory manager routines in RXB 2020 video Full documentation, examples and GPL source code are all included in the ZIP package. Cartridge image for classic99 emulator also included. Requires a GRAM device such as a GRAM Kracker or finalGROM99 cartridge for running RXB on the TI-99/4A. RXB2020E.zip (Author: @RXB) My Little Compiler (MLC) TI-99/4A Library for using assembler-like language & routines from Extended Basic. Great for putting more power in Extended Basic programs. Now includes a precompiler for high-level language syntax. Demo Pong game and documentation included. The MLC development thread can be found here. Check out the video by @rocky007 on his MLC based TI-99/4A port of Kaboom! (Author: @moulinaie) The Missing Link 2.0 (TML) TI-99/4A The zip archive contains "The Missing Link 2.0" and its documentation. This was published by Texaments in 1990. It gives the XB programmer easy access to the bit mapped features of the 9918 VDP. Full color cartesian graphics, turtle graphics, sprite graphics (32 sprites with auto motion) are supported. Text can be displayed on screen with fonts having sizes ranging from 4x6 pixels to 8x8 pixels. The manual is updated with many previously undocumented features. A tutorial called "Potatohead" is included. There is a loader that embeds A/L programs in high memory - they can be saved as an XB program and run directly out of high memory. (Author: @senior_falcon) TidBiT - BASIC/XB Translator win, linux, OS X A translator program that reads a program written in a custom, structured form of BASIC and translates it to a BASIC / Extended BASIC program. PHP required when doing a local installation. Check here for the latest revision, installation instructions included. (Author: @matthew180) Kull KXBII Extensions TI-99/4A Kull Extended BASIC II programming package. High resolution graphics and clock support in Extended Basic. Documentation by @hloberg. Extended BASIC - Manuals COMPUTE!'s Programmer's Reference Guide to the TI-99/4A PDF TI-Basic programming manual touching graphics and sound. COMPUTE!'s TI Collection volume One PDF The online version can be found here. Best of TI-Basic programming by C. Regena Texas Instruments TI-99/4A user reference guide PDF The official user reference guide with details how to setup and connect your TI-99/4A. Includes an introduction on the TI-BASIC programming language. Extended Basic reference manual PDF The official extended basic manual, explaining the 40 new or expanded commands, sprites, etc. Check here for the online version with command lookup functionality. MG Night Mission PDF Advanced tutorial on how to program an arcade game in Extended Basic. MG Smart Programming Guide for Sprites PDF Advanced tutorial on how to efficiently use sprites in Extended Basic. C - Software C99 v4 TI-99/4A C99 is a small C compiler for the TI-99/4A written by the famous C. Pulley. Documentation included. C99C - C99 cross compiler and optimizers win C99C is the enhanced PC version of the C99 compiler for the TI99/4A home computer. Also included are multiple optimizers for compacting the generated assembly source (C Optimizer, Function Call Optimizer, ...) (Author: @F.G. Kaal) GNU C Compiler (GCC) win + linux + osx GCC for the TMS9900 allows you to cross-compile C programs on your PC (Linux, OSX or Windows) for the TI. Insomnia's release contains a set of patches against GCC 4.4. Just check out the code from the GCC project, apply the patches and build according to the build instructions for your platform and you're on your way to write programs and games for the TI in a high level language that rival the speed of assembly. And if you need just that little bit extra in terms of speed, you can always inline TMS9900 assembly for the critical sections of your code and compile everything with the same toolchain. For access to the VDP, the SN76489, etc... you can use Tursi's ti99 library, which you can find in the GCC thread. Hop over to the INSOMNIA LABS blog for background information on this port. Check the "Setting up the GCC compiler for the TI-99/4A" video by @Tursi for detailed steps on how to build and install GCC on your Windows PC. You can now download the cygwin binary port of the older TI GCC 1.10 for Windows here. (Thanks @lucien2). (Author: @insomnia) Fortran - Software 99-9640 Fortran TI-99/4A & Geneve The zip archive contains LGMA Products' FORTRAN v4.4 in both a version for the TI-99/4A and the Geneve 9640 computer. Documentation in PDF format included. The discussion thread on Atariage can be found here. Special thanks to: dano Forth - Software Turboforth TI-99/4A A brand new implementation of the Forth langugage for the TI-99/4A. The Forth system itself is written in assembler and is optimized for speed. It runs from the cartridge space so there's plenty of space for your program in the 32K memory expansion. Check TurboForth.net the companion web site for the TurboForth system. Click here for seeing some Turboforth video tutorials. (Author: @Willsy) TI Forth Instruction Manual "2nd Edition 2013" PDF 2012 enhanced version of the original TI Forth Instruction Manual in PDF format by @Lee Stewart. Look here for details on manual improvements, etc. The updated TI-Forth system disk can be found here. (Author: @Lee Stewart) fbForth TI Forth with File-based Block I/O zip fbForth uses Level 3 file I/O for I/O of Forth blocks. It also implements 80-column text mode if you have a system with that facility. fbForth 32KB 2.0.X ROM cartridge available. (Author: @Lee Stewart) CAMEL99 V2 Forth TI-99/4A Multi-tasking Forth for the TI-99/4a. CAMEL99 Forth has been built as an educational tool for those who are interested in how you could cross-compile Forth to a different CPU using an existing Forth system. Camel99 Forth Development thread on Atariage can be found here. (Author: @TheBF) GPL - Manuals/Tutorials GPL Programmers Guide PDF The original GPL programming reference manual from Texas Instruments. Covers all opcodes and advanced stuff like coincidence detection, I/O routines, etc. GPL HOW 2 Series video A complete series on how to program GPL (Graphics Progroamming Language) on the TI-99/4A. Each tutorial has its own support package with example code, GPL assembler, etc. Video tutorials done by Rich, the programmer of Rich Extended Basic. (Author: @RXB) GPLHOW2A - Introduction video / zip GPLHOW2B - Sprite demo video / zip GPLHOW2C - How to make a Screen Editor like TI Writer or Editor Assembler video / zip GPLHOW2D - Editor Assembler TI BASIC support.video / zip GPLHOW2E - DMII cartridge upgrades and how GPL works video / zip GPLHOW2F - TI Basic to GPL. Converting a TI Basic program to GPL video / zip GPLHOW2G - TI Basic CALL SOUND to GPL video / zip GPLHOW2H - Simultaneous sound lists and interrupt timer in GPL video / zip GPLHOW2I - XB2GPL demo of a XB game Baloons converted into a GPL program video / zip GPLHOW2J - Update to GPLHOW2I and adds a automatic music to the game from the last demo video / zip GPLHOW2K - How to make XB Program Image files into I/V 254 files video / zip TI-Intern PDF Details on "Monitor", the OS of the TI-99/4A. Disassembly of console ROM/GROMS and GPL interpreter. Has details on interrupt routine, utility subprograms, basic interpreter, etc. The thread "The TI-99/4A Operating System" is an ongoing community project for commenting the source code of the TI-99/4A ROM and allowing it to be assembled with todays' assemblers. LOGO - Manuals TI-LOGO programming manual PDF The official TI-LOGO programming manual. The online version can be found here. Pascal - Software Turbo Pasc'99 TI-99/4A The zip archive has the patched version of Wiposofts Turbo Pasc'99 which you can run on your favorite emulator or on the TI-99/4A itself. While Turbo Pasc'99 is not as complete an implementation of Pascal as the UCSD Pascal system, it does have the advantage of not requiring any special hardware other than 32K RAM and a disk drive, and will likely meet the programming needs of most TIers. Check here for an english translation of the german documentation. This version is started by running the Editor Assembler #EA5 program image DSK1.TP99A Special thanks to: @Vorticon, @apersson850, @retroclouds and @lucien2 Pascal - Manuals UCSD Pascal ZIP + PDF The official UCSD Pascal programming manuals and disks. The zip file (70 megabytes) contains all manuals in PDF format. Here are the PDF manuals for online viewing: Compiler, Editor, Filer, Utilities, Assembler, Linker, p-code card The UCSD system disk images in v9t9/MESS format can be found here. Note that you need the UCSD P-code expansion card for running UCSD Pascal on the TI-99/4A. Thierry Nouspikel has lots of information on the technical implementation of UCSD Pascal on the TI-99/4A. Check here for details on the P-Code card and here for details on the P-Code system software. Also a lot of details on UCSD Pascal in general (p-system vm, documentation, cross compiler, ...) can be found here. 3. Technical Documentation Hardware TMS9900 Microprocessor Data Manual PDF Data Manual on the TMS9900 16-bit processor. The TMS9900 is the CPU used in the Texas Instruments TI-99/4A Home Computer. Contains instruction execution times, opcode size, etc. TMS9901 Programmable Systems Interface Data Manual PDF Data Manual for the TMS9901, Interrupt and I/O interface controller VDP Programmer's guide PDF The official programmer'a guide for the TMS9918A and its variants. The 9918A is the Video Display Processor chip used in the TI-99/4A and several other home computers + game consoles of that era. SN76489 sound chip datasheet PDF Data sheet for the SN76489 sound generator. The TMS9919 in the TI-99/4A is close to being identical with the SN76489. TMS5220 Speech Synthesizer Data manual PDF Data manual for the TMS5220 chip used in the TI-99/4A speech synthesizer device. Interface standard & Design Guide for TI 99/4A peripherals PDF The purpose of this manual was to consolidate all information available in the public domain on the design and development of peripherals for the TI 99/4A computer into one reference. Also covers the software aspects such as DSR architecture, PABs, etc. ROM Command Module Guide 2.0 PDF This manual provides a complete description of how Assembly Language User Programs need to be written so that the object code can be downloaded into (EP)ROM's which canthen be used in the "(EP)ROM module", a module designed to be used with the TI 99/4A Home Computer. TI Hardware Manual txt Compilation of valuable hardware & programming info on Myarc memory cards, Disk Controllers, Hard Drives, CPU identification (TMS9900, TMS9995, TMS99000) in assembly language, etc. DSR (Device Service Routine) / Disk & File Management Device Service Routine Specification for the TI-99/4(A) Personal Computer PDF Functional Specification for the 99/4 Disk Peripheral PDF Software Specification for the 99/4 Disk Peripheral PDF GPL Interface Specification for the 99/4 Disk Peripheral PDF File Management Specification for the TI-99/4 Home Computer PDF File Operations in assembly language 4. Homebrew Hardware Graphics & Sound F18A Video Display Processor The F18A is a FPGA based hardware and pin compatible replacement for the TMS9918A/TMS9928/TMS9929 VDP's (Video Display Processor). Besides VGA output it offers enhanced functionalities such as 80-column mode, additional video resolutions, hardware register scrolling, an embedded TMS9900 compatible GPU, etc. The development thread on Atariage, which includes the F18A programming documentation can be found here. The store on code|hack|create has the details on F18A availability, costs, etc. (Author: @matthew180) SID Master 99 sound synthesizer card The SID Master 99 is a new sound synthesizer expansion card for the Peripheral Expansion Box. It integrates the famous MOS 6581 or 8580 SID chip (as used in the Commodore 64 home computer). SIDPLAY99 sound player software available for use with this expansion card. The store on DSAPC has the details on Sid Master 99 availability, costs, etc. (Author: @marc.hull) Homebrew cartridge boards There are a number of Homebrew cartridge boards available to the users of the TI-99/4A now. Each has its own advantages and disadvantages from a usability standpoint, and some earlier types are only available by having your own made. To read the PCB layout files mentioned below, you need the ExpressPCB software which is available for free. Check here. The files are currently not released in Gerber/Excellon format, but can be converted to it using the RobotRoom Copper Connection software, available here. Note that to convert files to Gerber format you have to have the licensed version of the software ($50). 16K board PCB file The first of the new cartridge boards is the 16K board designed by @acadiel and @Stuart. This board used an inverted output from a 74LS379 to select between two 8K banks at >6000 in the TI memory map. The banks are selected by writing to >6000. This board allows most of the third-party cartridges designed for the 99/4A to be replicated. Further details on this board (components, EPROMS, software, etc.) can be found in: 16k_board_details.rtf FlashROM 99 PCB file, firmware source code The TI 99/4A Flash ROM Cartridge, or FlashROM 99 for short, is a cartridge for the TI 99/4A home computer that allows for running ROM cartridge images stored on an SD card. The FlashROM 99 supports ROM-only images of up to 32K that use the write-to->60xx bank switching scheme. It will not work with programs using GROMs or CRU-based bank switching. The cartridge does not require the Peripheral Expansion Box and runs on both PAL and NTSC consoles. Discussion thread on Atariage can be found here. (Author: @ralphb) FinalGROM99 PCB file, firmware source code The TI 99/4A FinalGROM Cartridge, or FinalGROM 99 for short, is a cartridge for the TI 99/4A home computer that allows you to run ROM and GROM cartridge images from an SD card. It succeeds the FlashROM 99 released in 2016. The FinalGROM 99 supports ROM images, GROM images, and mixed images of up to 1 MB in size that use the write-to-ROM bank switching scheme. The cartridge does not require the Peripheral Expansion Box and runs on both PAL and NTSC consoles, including modified consoles with an F18A. It will also run on v2.2 consoles and enables those to run ROM-only programs. The development thread on Atariage can be found here. (Author: @ralphb) 5. Utilities (file transfer, graphics, sound, ...) File Transfer TIImageTool win + linux TIImageTool is a tool that allows you to open disk image files as used with many emulators, and to work on them with common disk operations (like cut/copy/paste of files). It is particularly tailored for use with MESS but can also be used with other emulators. Has support for v9t9 format, PC99 format, CHD format, working with files & directories, Archiver support (can process Archiver files on the images), ... This utility needs the Java Runtime Environment available for free at Oracle. Supports Cf7a+ card images. (Author: @mizapf) TI99Dir win TI99 filemanager for windows. Great for transferring disk images to the TI-99/4A. Supports Cf7a+ cards and Cf7a+ card images. (Author: @F.G. Kaal) TiDisk-Manager OS X The TiDisk-Manager is a disk tool for disk images from floppy disks used by a TI-99/4A home computer. You will need an Apple Macintosh or Hackintosh running with Mac OS X 10.9 or newer. Has many features including file preview, export, etc. and even an interactive editor to disassemble program files and create good readable source code. The development thread on atariage can be found here (Author: @HackMac) Cf2k - Compact Flash 2000 TI-99/4A Cf2k (Compact Flash 2000) is a file manager for the TI99/4a with a CF7A+ compact flash adapter. With CF2k it is possible to protect/unprotect files, rename files/volumes, format volume, mount volume, copy/move/delete files, execute program files, ... Supports Cf7a+ cards. (Author: @F.G. Kaal) Graphics Convert9918 win Windows program for converting images into TMS9918A Graphics II (bitmap) mode. Output is in TI-Artist format or raw image/pattern dump. The article Modern Graphics on the 9918APDF gives an interesting overview on the techniques used in Convert9918. (Author: @Tursi) GraphiCV win/linux/osx Sprite Editor written in java. Draw your sprites on the PC and export them for use in Extended Basic and Assembler. Also supports export to Colecovision C format. Work with multiple sprite "layers" for creating multi-colored sprites. Click here for the GraphiCV development thread on atariage. Source code is also available at github. Check here. This utility needs the Java Runtime Environment available for free at Oracle. (Author: @unhuman) Magellan win/linux/osx TI-99/4A map editor written in java. This is the latest, updated, unofficial version. Draw your maps/screens on the PC and export them for use in Extended Basic and Assembler. Has a rich feature set: Import character set from '.PNG' or '.GIF' file, copy & paste, drawing functions, support for half-bitmap mode, Export in XB display merge format, etc. Possibility to export maps as data statements for Extended Basic and Assembler, binary export also possible. Click here for the Magellan development thread on Atariage This utility needs the Java Runtime Environment available for free at Oracle. (Author: @The Codex). Enhanced by @retroclouds, @sometimes99er, @Asmusr. Sprite Editor TI-99/4A TI-99/4A sprite editor written in C99. Runs from Editor/Assembler #EA5. Draw your sprites in an emulator or on the TI-99/4A machine. The zip file contains both the files for use in emulator and a TI disk image for easy transfer to the TI-99/4A. README file with detailed instructions included. You can see the Sprite Editor at work building some sprites: Jet Set Willyvideo and Parsecvideo. (Author: @Willsy) Sound VGM player Compresses VGM files into a format that can be played back on the TI using the included player from C and assembly. (Author: @Tursi) Mod2PSG2 Fully featured PC tracker for arranging music for the SN76489 and compatible sound chips. Can export to VGM and other formats. (Author: KonTechs/Martin) Sound List Ripper PC tool for ripping and playing back sound lists from TI files. Supports basic editing of sounds lists. (Author: @Asmusr) Sound list player Plays back sound lists from XB and assembly. (Author: @matthew180) Advanced Sound List Player TI tools for editing and playing back advanced sounds lists. (Author: @marc.hull) Speech QBOX Pro win QBOX Pro is the windows software that converts WAV files to LPC speech data for playback on the TI-99/4A speech synsthesizer. This is a 16bit windows application but it still runs in Windows 2000/XP/Vista. It requires the BWCC.DLL library which can be found here. BlueWizard osx LPC analysis tool for the Texas Instruments TMS5220 chip. Replacement for QBOX Pro. Has very good speech quality. Source code and pre-built install image for OS X can be found on gitHub here. Discussion thread on Atariage available here. (Author: @patrick99e99) Python Wizard unix/win This project is a python port (command line version and GUI) of the great macOS tool BlueWizard. It is intended to convert (voice) audio streams into LPC bitstreams used in the TMS 5220 chip or e.g. in the Arduino library Talkie. Now you can generate your own LPC streams and make your chips say the things you want them to. (Author: @deladriere) TI Synth Editor win TI LPC speech pattern exploration and editing app in the spirit of the venerable Speecoder. Watch the "How To" video to create custom speech synth here (Author: @pixelpedant) Editors Notepad++ win Notepad++ is a free source code editor that supports several languages. Runs in Windows environment. Notepad++ syntax highlighting file win Syntax highlighting file for Assembler and Extended Basic to be used with the Notepad++ text editor. 6. Tutorials Assembly language Building a multi-bank ROM image PDF Tutorial on compiling a 32K bank-switched cartridge ROM image starting from assembly source code (deref utility included). How to implement an assembly sound player for XB web Very well written tutorial on how to implement an assembly sound player for Extended Basic. It covers the tools needed and steps involved. Commented assembly source code Not a tutorial in the classical sense, but the commented source codes of the below games should help you get the idea. Pitfall! source code ZIP Munchman source code PDF TI invaders source code PDF TI Invaders source code TXT PARSEC source code PDF Moon Mine source code PDF Hopper source code PDF Thank you @Ksarul for your OCR work on the PARSEC source code. Thank you @Stuart for your OCR work on the TI-Invaders source code and tweaking it for assembly with Winasm99. Thank you @dphirschler for pointing me to Hopper and Moonmine source code. TMS9918/TMS9928 Video Display Processor TMS9918/9928 video modes video Video tutorial explaining the supported graphic modes of the video processor used in the TI-99/4A. TMS9918/TMS9928 Sprites and Characters video Video tutorial about the use of sprites and character patterns in the different video modes. TMS9918/TMS9928 How to create a bitmap title screens video Video tutorial on how to create a bitmap screen for games. Speech Synthesizer Convert WAV file for playback using speech synthesizer video Video tutorial on how to use QBOX Pro to convert a 8kHz mono WAV file to LPC speech data for playback on the TI-99/4A with the speech synthesizer device. It shows how to embed the LPC byte stream into your own assembly language program. Compilers The Wilhelm Basic compiler video Video tutorial on how to compile a basic program to assembly language. (Author: @Opry99er) File transfer (TI99->PC) RS232 File Transfer video Video tutorial on file transfer from the TI-99/4A to the PC using a serial connection cable. (Author: @Opry99er) (PC->TI99) RS232 File Transfer VIEW PART 1 / VIEW PART 2 video Video tutorial split in 2 parts dealing with file transfer from the PC to the TI-99/4A using a serial connection cable. In detail: DL a game from TI Gameshelf, Use ARC303G to unarchive it, Test in Classic99, Transfer using QModem and MFM, Running game on TI. (Author: @Opry99er) 7. TI-99/4A related websites TI-99/4A @ wikipedia Introduction and basics of Texas Instruments TI-99/4A Home Computer. ninerpedia Wiki with information on MESS and its multicart format (RPK). Home of the TI-FAQ. Thierry Nouspikel's Tech Pages Probably the best TI hardware and software tech page. It has a wealth of technical details on all things TI-99/4A. This includes GPL, GROM, keyboard scanning, speech, etc. You can also download the full site as a zip file for offline viewing. Mainbyte's home of the TI-99/4A Very good tech site with many detailed pictures and reference area. Includes various projects for upgrading your TI-99/4A, e.g. build a supercart cartridge. Jon's hexbus page Several hardware projects including pictures. Home of the 64K bank-switched cartridge project. (Author: @acadiel) [code|Hack|Create] New website run by Matthew of the Atariage group. The site covers many new hardware projects as the F18A FPGA based VDP and Bank-switch mini 256K. There's also a store where you can buy cartridge PCB's and other funky stuff. (Author: @matthew180) The nanoPEB & CF7+ Website The official website. Has the documentation, tools and some source code of the popular TI-99/4A Compact Flash device. TurboForth.net TurboForth.net is the companion web site for the TurboForth system written in TMS9900 Assembly Language by Mark Wills for the Texas Instruments TI-99/4A computer. TI projects page Several hardware and software projects for the TI-99/4A. Home of TI-99Dir, TI99HDX and several other must-see projects. (Author: @F.G. Kaal) TI-99/4A Home Computer Book Archive Site where you find many books about the TI-99/4A not seen elsewhere, all collected by @airernie and now hosted by @acadiel (Author: @airernie) TI-99/4A Game Shelf Provides a gallery of interesting games with images of the opening screen as well as an in-play snapshot, along with a brief review tested on a real TI 99/4A system. Hardware requirements are also listed. Has many good Extended Basic games. (Author: @Vorticon) WHTech WHTech is the primary archive - though it's a bit overwhelming. But pretty much all software, hardware docs, etc, are available there. 99er.net Site with useful file archive and forum functionality. comp.sys.ti Covers all TI devices, including calculators.
  3. We've now reached a compact bit of code in the Dealer Demo that provides an assembler to Forth. And the assembler in Forth is a thing of beauty indeed. Written by Bill Ragsdale (as was most of the Forth kernel), it provides an assembler that can produce surprisingly readable code without the use of labels. In essence it implements high-level assembler: Recall TRAVERSE. In traditional assembler, it was written as: 154A: 4C 15 TRAV .WORD *+2 154C: B4 00 LDY 0,X 154E: 98 TRAV1 TYA 154F: 18 CLC 1550: 75 02 ADC 2,X 1552: 95 02 STA 2,X 1554: B5 01 LDA 1,X 1556: 75 03 ADC 3,X 1558: 95 03 STA 3,X 155A: A1 02 LDA (2,X) 155C: 10 F0 BPL TRAV1 155E: 4C 4D 0E JMP POP In Forth assembler, it might be written as: CODE TRAV ,X 0 LDY, BEGIN, TYA, CLC, ,X 2 ADC, ,X 2 STA, ,X 1 LDA, ,X 3 ADC, ,X 3 STA, X) 2 LDA, 0< NOT UNTIL, POP JMP, ;CODE Notice that we didn't need a label we simply used BEGIN, to mark the beginning of a block and UNTIL, to mark the end. The Forth assembler also has IF, ELSE, THEN, which behave as expected. This is flexible enough to handle most assembly constructs without ever resorting to labels. It also uses a Forth-like syntax, with RPN ordering for the assembler codes, and the opcodes always ending in comma, since the effect is similar to the comma operator which puts data into memory in Forth. While I wouldn't want to write a large program this way, this is much more convenient than the USR function in BASIC. Another interesting implementation detail is that all opcodes are split into two sets. The first set, encoded using the word CPU, are most of the traditional one-byte 'immediate' mode opcodes, and have the opcode byte value attached to them. The remaining opcodes, encoded using the word M/CPU, use a word and a byte for each of these to select the appropriate opcode depending on the current mode and whether to emit 0, 1 or 2 additional bytes taken from the stack. This is remarkably compact, thanks to the <BUILD … DOES> construct in Forth which we discussed in an earlier post. You can read about this assembler in an article by Bill Ragsdale himself. It appeared in the September 1981 issue of Dr. Dobbs Journal (a issue dedicated to Forth), as well as the January 1982 issue of Forth Dimensions (v.3, number 5). The implementation itself was available earlier, since the Dealer Demo dates from late 1980, and the screens for the assembler date to June 1979 and earlier. It opens with: If you compare the published Ragsdale implementation with the assembler in Dealer Demo, only a few minor differences appear. The word VS was added, to give symbolic access to the overflow branches (BVS & BVC, an oversight in the original assembler), and the word END-CODE was renamed to C;. In Dealer Demo, the assembler occupies $25a0 - $2be4, or about 1.6k. So the Forth kernel and its assembler are about the same size as the Atari Assembler/Editor cartridge. Atari Forth on cartridge, that would have been an interesting product to see! dealerdemo.lst
  4. From the album: CAMEL99 Forth

    Results of program to calculate day of week
  5. Hi together, For the preservation project and the Wiki, we search for just a single file: FLOAT.OBJ, please see the picture attached. It is from Hofacker/ELCOMP and was sold additional to their Power FORTH package, which is the same as fig-FORTH. It was called: Floating Point Package for POWER Forth #7230. So, even if someone has the FLOAT.OBJ file from the fig-FORTH package, that would help us very much. Thank you all for your help. 🙂
  6. All... I have a first draft (attached) of my updated version of the (now finished---see later or click link-->) TI Forth Instruction Manual in PDF format. I am working on it in Open Office Writer (ODT format), but it won't look right if someone reading it does not have the fonts I used. I think the PDF will work better. I have elaborated parts of the manual, but I have not started an index, yet. One problem with the indexing in OOO Writer is that I have not yet figured out how to sort the index by ASCII codes. Writer wants to put non-alphabetics at the end and I want them as the TI Forth Glossary has them, i.e., in ASCII order. Anyway, I am very interested in any feedback on this draft, particularly where I have added or changed information and whether you think an index would be useful. ...lee
  7. This is the first of several tutorials to help those new to Forth, fbForth 2.0 in particular, to understand the language and its programming environment, as well as to gain some facility with it. fbForth is based on TI Forth, which was derived mostly from FIG-Forth with some influence from Forth-79. There are more recent Forth standards; but, compatibility with TI Forth was the prime concern. The biggest difference between TI Forth and fbForth is that fbForth is a file-based system, whereas TI Forth reads/writes directly from/to disk sectors without regard to any file structure. This is dangerous for the health of the disk and the user, especially, if you were to inadvertently use a disk with files on it for other systems. It also makes it difficult to exchange programs. Not only does fbForth coexist with as many unrelated files as will fit on a disk, you can create many different blocks files on the same disk as long as there is room. A TI Forth disk cannot contain anything but Forth blocks. I suppose that is more than sufficient for preamble. Let’s get on with learning fbForth. To operate the fbForth 2.0 System, you must have the following equipment or equivalent: TI-99/4A Console Monitor fbForth 2.0 Module (see this forum thread’s post #1 to get yours: fbForth—TI Forth with File-based Block I/O ) Peripheral Expansion Box (PEB) with 32 KiB Memory Expansion Disk Controller with 1 or more Disk Drives RS232 Interface (optional) Printer connected to RS232 interface (optional) If you wish to work through these tutorials but do not have this equipment or equivalent (CF7+ or nanoPEB, which substitutes for a PEB with the first three PEB items above), all of the software and firmware are available in the above-referenced thread for the Classic99 and MAME emulators. I also can supply the same for CaDD Electronics’ PC99 emulator, if you need it. It is a good idea to have a copy of fbForth 2.0: A File-Based Cartridge Implementation of TI Forth (the manual—available in the above forum thread) for reference, especially for looking up commands (Forth words—more below) in the glossary (“Appendix D”). Please note that the glossary is in ASCII order, which is listed at the bottom of every glossary page. Also, if you have a copy of the first edition of Leo Brodie’s excellent beginner’s book on Forth: Starting FORTH, “Appendix C” of the manual cross-references conflicts with fbForth 2.0. After powering up: and selecting “2 FOR FBFORTH 2.0:12” for 40-column text mode, say, If FBLOCKS is found, you will be presented with: followed by (after your color choice): If FBLOCKS cannot be found, you will see: The system blocks file is FBLOCKS and must be present in DSK1 for the first series of screens to display. If fbForth does not find it there, the second screen displays. fbForth will still work just fine. You just won’t be able to display the menu of loadable utilities with MENU until you make FBLOCKS the current blocks file, which you can do by typing the following at the console’s flashing cursor if FBLOCKS is in DSK2, say: USEBFL DSK2.FBLOCKS 1 LOAD You can force fbForth to look for FBLOCKS on another disk at boot time if you hold down the number of that disk immediately following your startup-screen selection. Notes about the welcome screen: The first two lines and the last line of the welcome screen appear regardless of the presence of FBLOCKS. The version number of the cartridge includes the revision number after the ‘:’. The line beginning with “FBLOCKS mod:” comes from block #1 of FBLOCKS and will always reflect the current date of the system blocks file, FBLOCKS, which is always kept up to date in the above forum thread. Commands in Forth are called “words”. You will note that Forth words included in the normal text of these tutorials appear in boldface and are surrounded by spaces. This may look awkward when the space after a word precedes a comma, period or similar punctuation mark; but, since those punctuation marks are also Forth words, this practice avoids ambiguity. Speaking of spaces around words, that is how the Forth text interpreter ( INTERPRET ) knows it has the next word to look up in its dictionary (linked list of already defined words). It searches the dictionary from the most recently defined word to the very first word defined. In fbForth, that word is EXECUTE . See what I did there? EXECUTE has a space after it and it’s before a period. You are in the hands of the Forth text interpreter in two places, viz., at the console’s blinking cursor and when a block is loaded by the word LOAD . The input stream is viewed by the interpreter as a series of tokens separated by one or more spaces. If the interpreter finds the word, it executes the word and gets the next token. If the interpreter cannot find the token as a word in the dictionary, it checks to see if the token can be converted to a number in the current radix (number base). If it can, it pushes that number onto the parameter stack, which is often termed “the data stack” or, simply, “the stack”. The parameter stack, by the way, consists of a stack of cells, much as a stack of plates in a cafeteria, with the same restriction: You can only readily remove (pop) the top plate, i.e., the last cell on the stack is the most accessible and thus the first one popped off. This Last_In_First_Out situation is known as LIFO. Furthermore, in fbForth, a cell is 16 bits or 2 bytes wide. In computer parlance, 2 bytes constitutes a word; but, to avoid confusion with talking about Forth commands as words, we will generally use “cell” instead of “word” to mean “2 bytes”. Finally, if the token is not a word in the dictionary and it cannot be converted to a number, the interpreter gives up and issues an error message that repeats the word it could not find followed by a question mark. It also clears the stacks (parameter stack and return stack, about which more later) and, if loaded from a blocks file, leaves two numbers on the parameter stack to aid in finding where in the input stream the error occurred. These numbers are the contents of user variables IN (the position in the input stream immediately following the token causing the error) and BLK (the block number being interpreted). When loading a block that aborts with the error report just described, you can type WHERE to put you into the editor with the cursor at the error. We will talk more about the editor in another lesson. Otherwise, you may just want to type SP! (stack pointer store) to clear the parameter stack. After you finish entering one or more successfully interpreted words and/or converted numbers with <ENTER>, the interpreter will display “ ok:n” to let you know its success. The ‘n’ after the colon is the depth of the parameter stack, i.e., how many numbers are currently on the stack. Here are a few lines typed at the console: The first line is from just tapping <ENTER>. Everything is OK with nothing on the stack. The second line pushes ‘4’ onto the stack and indicates all is well with one number on the stack. The third line pops and prints ( . ) the number, showing the stack as now empty. The last line obviously was not understood by the interpreter, hence the error message. Let’s wind this lesson up with showing you the most common way to define a new word in Forth. The defining word we will use is : . : starts a high-level Forth definition, which is terminated with ; . The first token that must follow : is the name for the new word. fbForth is case-sensitive. HELLO is different from hello . In our definition, we will use the word .” , which means “print string”. ." accepts any characters into the string except for " , which is the terminator. As soon as it sees the " , it prints the string: We will now define the word HELLO and add CR to the definition before and after the print-string code. This will put the cursor at the beginning of the next line each time it is executed. Typing the newly defined word, HELLO , will execute its contents: Remember that Forth words must be separated by spaces. The Forth Interpreter looks in the input stream for the next word until it finds a space or the end of the input stream. Upon finding a space, it then looks for the next word that starts with the next, non-space character. There are six words used in our definition of HELLO above, which are: : HELLO <---the word we are defining CR .” CR ; That’s all for now.
  8. Forth: Bouncing some ideas around (#3) In this short tutorial we'll start with something really simple: We'll get a bouncing ball moving around on the screen. As we develop our words, we'll test them as we go, rather than run the whole program in one go only to find that it doesn't work and wonder where the bugs could possibly be. When we've got the ball moving around, we'll add a bat that we can use to hit the ball. Think old style breakout. We're going to restrict ourself to characters in 32 column mode. We'll look at sprites in a future lesson; I'll just say this: Sprites are in some respects simpler than characters when it comes to moving them around, because you don't need to erase them, so there's great difficulty coming down the line regarding sprites. If your curiosity cannot be contained however, have a look at the sprite tutorial here: http://turboforth.net/tutorials/graphics.html#95 So, here's a program that bounces a ball (a zero character, actually, at the moment I'm into a rather odd "less is more" period when it comes to graphics, and am particularly fascinated with ASCII graphics; check out some of those old ZX81 games and you'll see what I mean) around the screen, inside a frame, just to keep things tidy. First in TI BASIC so that we have something as a reference: 10 CALL CLEAR 20 REM DRAW FRAME AROUND SCREEN 30 CALL HCHAR(1,2,ASC("-"),30) 40 CALL HCHAR(24,2,ASC("-"),30) 50 CALL VCHAR(2,1,ASC("|"),22) 60 CALL VCHAR(2,32,ASC("|"),22) 70 CALL HCHAR(1,1,ASC("+")) 80 CALL HCHAR(1,32,ASC("+")) 90 CALL HCHAR(24,1,ASC("+")) 100 CALL HCHAR(24,32,ASC("+")) 110 REM DEFINE BALL VARIABLES 120 BALL_COL=2+INT(RND*29) 130 BALL_ROW=2+INT(RND*21) 140 XDIR=1 150 YDIR=1 160 REM ERASE BALL 170 CALL HCHAR(BALL_ROW,BALL_COL,32) 180 REM CALCULATE NEW BALL POSITION 190 BALL_COL=BALL_COL+XDIR 200 BALL_ROW=BALL_ROW+YDIR 210 CALL HCHAR(BALL_ROW,BALL_COL,ASC("0")) 220 REM CHECK FOR EDGE OF SCREEN 230 IF (BALL_COL<3)+(BALL_COL>30)THEN 260 240 IF (BALL_ROW<3)+(BALL_ROW>22)THEN 290 250 GOTO 170 260 REM REVERSE X DIRECTION 270 XDIR=-XDIR 280 GOTO 170 290 REM REVERSE Y DIRECTION 300 YDIR=-YDIR 310 GOTO 170 We'll now look at how we could re-create this program in Forth. Note how I have separated the code above into distinct sections (using blank lines here for clarity). We'll divide (or "factor") the Forth version into pretty much the same sections, testing them as we go. Drawing the Frame Around The Screen Okay, in the program above, we need to clear the screen and then draw some lines and characters. Note that I've used the ASC function to make the code a little more "self-describing" who wants to waste time looking up ASCII codes, right? In Forth, there's an extra step, as we first need to tell the system to go into 32 column mode (TurboForth and fbForth default to 40 or 80 column text modes). The (TurboForth) command to change graphics modes is GMODE. Mode 0=40 column text mode 1=32 column graphics mode 2=80 column text mode So, lets create a word called FRAME which sets up the screen and draws the frame. : FRAME ( -- ) \ set up screen and draw frame 1 GMODE \ 32 column text mode 0 1 ASCII - 30 HCHAR 23 1 ASCII - 30 HCHAR 1 0 ASCII | 22 VCHAR 1 31 ASCII | 22 VCHAR 0 0 ASCII + 1 HCHAR 0 31 ASCII + 1 HCHAR 23 0 ASCII + 1 HCHAR 23 31 ASCII + 1 HCHAR ; Things to note in the above code: : FRAME - this part says "hey, here's a new word called FRAME; ( -- ) this is comment that tells us that word has no effect on the stack - it takes nothing from the stack and puts nothing on the stack; The \ (backslash) is a comment. When TurboForth see this is treats eveything following it as a comment; Screen coordinates are zero-based, whereas in BASIC they are one-based Read the code from left to right, top to bottom. You can have multiple instructions on the same line; The "arguments" to the function/word (in this case HCHAR and VCHAR) come BEFORE the word itself. Why? Because the words/functions take them from the stack, so they need to be on the stack BEFORE the word itself executes; The command ASCII looks at the character in front of it and pushes the appropriate ASCII value to the stack. So ASCII * is like ASC("*") in TI BASIC; Spaces are ESSENTIAL in Forth. One or more spaces MUST separate words and numbers from each other. Forth cannot recognise 99STARS if you really mean 99 STARS; The semi colon at the end says "Okay, I'm done defining my FRAME word, thank you very much, add it to the dictionary" (where all the Forth words and their code are stored). At this point, you've added a new word to the language called FRAME. Now that it exists, any other word that you create can use it. So how do we use it? We "name" it. I.e. we type its name. Forth will do the rest. If we type FRAME on the command line (i.e. when the cursor is sitting there blinking at you) then it will immediately execute it. This is the same as typing something in TI BASIC without a line number in front of it. TI BASIC will just execute it (or try to); If we type FRAME inside another definition, then it will be compiled for execution later. This is the same as putting a line number in front of something in TI BASIC. TI BASIC will store it and run it later. So, assuming you have typed the above in (the best way is to use Classic99 and just copy the text above and paste it into TurboForth) you can just type FRAME (or frame - TurboForth is not case sensitive by default (you can turn it off)) and press enter and the code will run. So, hopefully, you have a neat frame around the screen and TurboForth is saying OK at you and furiously flashing its cursor at you. We can now move on to the next bit. Note that TurboForth is still in 32 column mode. You can leave it in 32 column mode if you like, but you might be more comfortable in 40 column mode on a real TI, or, if you have an F18A or you are using classic99, 80 column mode. Type either 0 GMODE and press enter, or 2 GMODE and press enter. The screen will clear and the mode will be changed. Let's move on. We've tested FRAME, it does just one thing and has no variant behaviour, so it either works or it doesn't. The Value of VALUEs The next step of the program sets up the initial ball and row and column variables, let's remind ourselves: 110 REM DEFINE BALL VARIABLES 120 BALL_COL=2+INT(RND*29) 130 BALL_ROW=2+INT(RND*21) 140 XDIR=1 150 YDIR=1 In TI BASIC, you can go ahead and just use a variable name. Forth is not like that. In Forth everything must be created first and stored in the dictionary, then you can reference it. So, we first need to declare our variables. However, in this tutorial, as it's very early days, I'm going to suggest that we use VALUES as they work more like variables in BASIC (i.e. they work with values; whereas variables in Forth work with addresses - that's for another day!) 1 VALUE BALL_COL 1 VALUE BALL_ROW 1 VALUE XDIR 1 VALUE YDIR So, this bit of code creates some VALUEs called BALL_COL, BALL_ROW, XDIR and YDIR respectively. The number is the initial value. Here's how 0 VALUE BALL_COL is evaluated: 0 is pushed onto the stack; The word VALUE (a built-in TurboForth word) executes. VALUE is programmed to *read ahead* of itself and use the word it finds there as the *name* of the value to create, so in this case, it creates a VALUE in the dictionary called BALL_COL. The initial value (0) that is on the stack is removed, and is used to initialise BALL_COL. If we had typed 99 VALUE BALL_COL then it would be initialised with 99. Declaration of VALUES/VARIABLES should NOT be done inside a definition. They should be by themselves. Some words are special in Forth and can only be used on the command line, just like (for example) NEW in TI BASIC, which can only be used on the command line. So, that's the declaration of the VALUEs done. You can test them by simply typing their name and pressing enter: BALL_COL <enter> Note that TurboForth responds with OK:1 meaning that 1 number is on the stack. What happened? You just "executed" a VALUE. Sounds strange doesn't it? I mean, you can't execute, say, variables in BASIC. What does it mean to execute a VALUE or a variable? Well, in the case of VALUEs in Forth, they are pre-programmed (once you have created them) to push their current value to the stack when you execute them. It's as simple as that. If you're used to OOP, think of VALUE as a class, and BALL_COL as an instance of class VALUE which took 0 as the constructor. Now, type YDIR <enter> TurboForth says OK:2 meaning that 2 numbers are on the stack. Let's look at them. There are two ways: The word .S will display what's on the stack, and leave them there for us (non-destructive) The word . (a dot/period) will take what's on the top of the stack and display it, removing it from the stack as it does so. Type .S <enter> TurboForth should display: 1 1 <--TOP OK:2 So, it's told you that 1 (YDIR) is on the top of the stack, and 1 (BALL_COL) is underneath it. Now, type XDIR .S <enter> TurboForth says 1 1 1 <--TOP OK:3 As an experiment, let's change the value of XDIR. Type: -1 TO XDIR See? That wasn't so hard was it? Pretty simple. Let's display the stack again: .S<enter> 1 1 1 <--TOP OK:3 Hang on. We changed XDIR to -1. Why does it still show 1 on the top of the stack? Surely it should display -1, right? No. The stack is a separate entity all by itself. It simply stores what you push on it. If you then change the value of something, good for you. You won't see it until you push it again. So, type XDIR again. TurboForth says OK:4 Now type .S and we get 1 1 1 -1 <--TOP OK:4 Okay, let's continue, but before we do, how do we clear those four numbers off the stack? There's a number of ways: type DROP DROP DROP DROP to drop (discard) them; type . . . . (four dots, separated by spaces) to display them (they get removed as they are displayed); Or, my favourite: type some random gibberish which causes TurboForth to empty its stack and display an error message: JFKDFDJKFJ ERROR: NOT FOUND OK:0 See? 0 items on the stack! Initialisation Right, now we need to initialise random starting row and columns for BALL_ROW and BALL_COL. So, let's make a word called SET_RC ("set row and column") that does just that: Type in or paste in the following: : SET_RC ( -- ) \ set row and column 30 RND 1+ TO BALL_COL 22 RND 1+ TO BALL_ROW ; That's it. How does this work? Well, this is a new word called SET_RC so when it is executed it will: Push 30 to the stack; Call RND which takes the 30 off the stack and uses it to generate a random number between 0 and 29. We need a random number between 1 and 30, so we call 1+ ("one plus") which simply adds 1 to the number on top of the stack. The phrase "TO BALL_COL" removes whatever is on the top of the stack and stores it in our VALUE which is called BALL_COL. The exact same technique applies for BALL_ROW, but using a different random number range. Let's test it. Make sure the stack is clear by typing some gibberish. Now type: SET_RC <enter> TurboForth says OK:0 - nothing was pushed to the stack. Let's see what was stored in BALL_COL and BALL_ROW: Type BALL_COL . BALL_ROW . <enter> (note the spaces between the dots) TurboForth will respond will respond with something like 13 9 OK:0, depending on what random numbers it chose. Let's look again, but this time using .S to show us the stack: BALL_COL BALL_ROW .S 13 9 <--TOP OK:2 This time, we executed the values directly, so they were pushed to the stack. Note how it's possible to put multiple commands on the same line separated by spaces. It's not necessary to enter them one at a time on separate lines, like this: BALL_COL BALL_ROW But you could if you wanted to. Placing commands/words together on the same line is a bit like using :: in Extended Basic to separate statements, only in Forth we just use spaces because there is hardly any syntax in Forth, you're in total control. Next, we need a word to erase the ball: Erasing The Ball : ERASE_BALL ( -- ) BALL_ROW BALL_COL 32 1 HCHAR ; There's not a lot of code there - it's hardly worth making a word just for this, *however* the advantage is that it means we can test it separately from the rest of our code. Let's test it: First, fill the screen with a character, using HCHAR like this: PAGE 0 0 ASCII * 960 HCHAR ERASE_BALL PAGE clears the screen (which resets the cursor position to the top of the screen) then we fill the screen (assuming you're in 40 column mode) with asterisks using HCHAR. You should see a hole somewhere where ERASE_BALL erased an asterisk. Good. So, how does it work? Well, during execution of ERASE_BALL, BALL_COL will push its value to the stack, BALL_ROW will push its value to the stack, we then push 32 to the stack (the ASCII code for a space character), and then we push 1 to the stack (the number of repeats - this is an optional parameter in HCHAR/VCHAR in BASIC, but NOT so in Forth). HCHAR then gobbles all those values up and uses them to draw a space at the correct place on the screen. Calculate New Ball Position Next, we need to re-create the calculation of the new ball position, and display of the ball. We're going to re-create this TI BASIC code: 180 REM CALCULATE NEW BALL POSITION 190 BALL_COL=BALL_COL+XDIR 200 BALL_ROW=BALL_ROW+YDIR 210 CALL HCHAR(BALL_ROW,BALL_COL,ASC("0")) : MOVE_BALL ( -- ) XDIR +TO BALL_COL YDIR +TO BALL_ROW BALL_ROW BALL_COL ASCII 0 1 HCHAR ; And voila. We have a new word, MOVE_BALL. Let's test it. We'll first make sure that the row, columns etc. are set to realistic values: 10 TO BALL_COL 10 TO BALL_ROW 1 TO XDIR 1 TO YDIR Note how I typed all that on one line. I could have typed: 10 TO BALL_COL 10 TO BALL_ROW 1 TO XDIR 1 TO YDIR But I'm lazy and impatient. Okay, so type in PAGE MOVE_BALL <enter> The ball should be displayed. Now type MOVE_BALL again. Now type MOVE_BALL MOVE_BALL MOVE_BALL MOVE_BALL <enter>. It should leave a trail of balls (ooer!). So how does it work? Here's the breakdown: XDIR pushes its value to the stack; The word +TO removes it and *adds* it to whatever is stored in BALL_COL; YDIR pushes its value to the stack; The word +TO removes it and *adds* it to whatever is stored in BALL_ROW; We then push the values of BALL_COL, BALL_ROW, the ASCII code for 0, and the number 1 (the number of repeats) to the stack; HCHAR removes them and does it's thing. Edge Detection Okay, we're nearly there! Next, we need to check if the ball is on a screen edge, and if it is then we reverse the direction of the ball in either the X or the Y direction. TI BASIC is rather terrible at this, because IF can only target a line number, so you're forced to separate the IF from the code that should run when IF is true. Just awful. In Forth we can do much better, however, the syntax may hurt your head a little bit. Not to worry, I'll break it all down. This is the TI BASIC code that we want to re-create: 220 REM CHECK FOR EDGE OF SCREEN 230 IF (BALL_COL<3)+(BALL_COL>30)THEN 260 240 IF (BALL_ROW<3)+(BALL_ROW>22)THEN 290 250 GOTO 170 260 REM REVERSE X DIRECTION 270 XDIR=-XDIR 280 GOTO 170 290 REM REVERSE Y DIRECTION 300 YDIR=-YDIR 310 GOTO 170 I'm going to create four new words: HIT_NS? (Hit north or south?) HIT_EW? (Hit east or west?) REV_XDIR (Reverse X direction) REV_YDIR (Reverse Y direction) Now, to be clear, we could write all of the above as one word. In fact, we could write the entire program as one word, but you'd have a terrible job trying to debug it! That's the advantage of breaking our code down ("factoring it") into small chunks. We can test them, and then just string them together at the end. So, here we go: HIT_NS? first: : HIT_NS? ( -- flag ) \ check hit on top or bottom of screen BALL_ROW 2 < BALL_ROW 21 > OR ; Whoa! That is some WEIRD looking code!! What on earth does it mean? Let me break it down step by step. There's only seven instructions, so it's not difficult to understand. It just LOOKS weird (most Forth looks weird, to be honest!) First, you need to be aware of the stack signature of this word: ( -- flag ) That means that this word takes nothing from the stack, but it does *leave* something on the stack. It leaves a flag (something that is either true or false). It's also very important to realise that the stack signature is a COMMENT. It's not a function parameter declaration like in C or Java. It's a comment that tells us *humans* what this word expects and leaves on the stack. Forth itself doesn't actually *know* what the word expects or leaves on the stack. It just dumbly tears through the code, obeying what it sees, and the results are the results. If the results are NOT what you expected, well, then YOU made a mistake somewhere! So, here we go: BALL_ROW pushes its value to the stack; We push the value 2 to the stack We execute the word < which means "is less than?" Is Less Than The word < or "is less than?" takes two values off the stack and compares them. If the first value is less than the second value, it pushes a -1 (true). If the first value is NOT less than the second value it pushes a 0 (false). It's as simple as that. So... at run time, BALL_ROW will be compared to 2, and if BALL_ROW *is* less than 2, the word "<" will push a -1 to the stack, otherwise it'll push a 0. We then do the same thing but using the word ">" is "is greater than?". Here, we compare BALL_ROW to 29, and if it *is* greater than 29, ">" will give us a -1, otherwise it'll give us a 0 on the stack. So, after the execution of these two lines of code, we'll end up with *two* values on the stack. The result of the < comparison, and the result of the > comparison. Next, we execute the word OR. OR takes two values off the stack and if the first value, or the second value, or both values are true, it pushes a -1 (true) to the stack. If both values are 0, it pushes a 0 (false) to the stack. So OR pushes the flag to the stack that we refer to in the stack signature for our word. We can prove that this will work at the command line, using numbers: -1 0 OR . (result is -1 (true) because one of the inputs to OR was true 0 0 OR . (result is 0 (false) because both inputs to OR were false). Let's have a quick look at the stack comments for these words: The word < has the stack comment ( a b -- flag ) which means flag will be true if a < b. A and b are removed from the stack. The word > has the stack comment ( a b -- flag ) which means flag will be true if a > b. A and b are removed from the stack. The word OR has the stack comment ( a b -- flag ) which means flag will be true if a or b are true. A and b are removed from the stack. All quite simple and logical. Okay, I'll rattle through the next one, it uses the exact same principle. It's just check East and West (left and right) screen edges. : HIT_EW? \ Hit east or west? BALL_COL 2 < BALL_COL 29 > OR ; I'll refrain from breaking this down as the principle is identical. I will however make a VERY brief detour and discuss paragraphs: Paragraphs: When we write in C or Java or assembly language we're used to leaving blank lines between lines of code. These are paragraphs, and they separate code up into logical blobs of code. Because Forth coded horizontally, we often use multiple spaces (two or three) on a line of code to break our code up into paragraphs. Consider HIT_EW? written in a horizontal style: : HIT_EW? \ Hit east or west? BALL_COL 2 < BALL_COL 29 > OR ; It reads okay (to someone that is used to Forth) but a better way to write it is like this: : HIT_EW? \ Hit east or west? BALL_COL 2 < BALL_COL 29 > OR ; That is probably a lot more readable to you. It certainly is to me. It's now much clearer that "BALL_COL 2 <" is a separate blob of code from "BALL_COL 29 >" because we separated them using paragraphs. It also takes up less screen space, and block space if you are using blocks. REV_XDIR (Reverse X direction) and REV_YDIR (Reverse Y direction) Okay, we're nearly finished. If you're having trouble reading all this stuff, spare a thought for the guy that had to write it! Let's finish up with REV_XDIR and REV_YDIR which will reverse the direction of the ball in the horizontal and vertical directions: : REV_XDIR ( -- ) \ reverse x direction XDIR NEGATE TO XDIR ; : REV_YDIR ( -- ) \ reverse y direction YDIR NEGATE TO YDIR ; You can probably see what these do. For XDIR, XDIR goes to the stack, NEGATE then negates whatever is on the stack (1 becomes -1 and -1 becomes 1 etc.) and then TO writes it back into XDIR. Same principle for YDIR. Let's test them: -1 TO XDIR REV_XDIR XDIR . TurboForth should display 1. I'll leave you to test REV_YDIR. Now we're going to write a word to roll these four words up. We'll call it CHECK_DIR for Check Direction. : CHECK_DIR ( -- ) HIT_EW? IF REV_XDIR THEN HIT_NS? IF REV_YDIR THEN ; I reckon right about now your head just exploded. I hope you're not sat on a bus as you read this. Just what in the name of Satan's Holy Trousers is that THEN doing at the END of a line? This doesn't make sense at all! Or does it? Well, actually it does. Here's a quick detour into how IF...THEN works in Forth. First, some BASIC to compare it to: 10 INPUT A 20 IF A < 10 THEN 50 ELSE 70 30 PRINT "FINISHED!" 40 END 50 PRINT "LESS THAN 10" 60 GOTO 30 70 PRINT "NOT LESS THAN 10" 80 GOTO 30 This absolutely vile, abominable code which forces you to go searching down the code for the appropriate line numbers (what if there was 100 lines of other code between them? Just vile) can be beautifully expressed in Forth thus: : CHECK ( n -- ) 10 < IF ." LESS THAN 10" ELSE ." NOT LESS THAN 10" THEN CR ." FINISHED" CR ; Go ahead and type that in. Note the stack signature. It needs a value passed into it from the stack: 9 CHECK 11 CHECK 10 CHECK You understand how this works now: We put 9 on the stack, then call CHECK which uses the 9 we just we put there, and so on. Let's break this CHECK word down: It puts 10 on the stack. Then "less than?" executes which will compare whatever we put on the stack to 10 and leave a true or false on the stack. IF then consumes whatever "less than?" left on the stack. If it was a TRUE then the code after the IF will execute, ELSE the code after the ELSE will execute, THEN normal execution will continue to the end of the word. The following should illustrate how this works, and it's important to realise that THIS IS VALID FORTH CODE (assuming the following words existed): SUNNY? IF GET-SHADES ELSE GET-JACKET THEN GO-OUTSIDE If you read that out loud, it reads like English. And well crafted Forth code, if factored nicely (which takes experience) will often read very close to English. It's clear from the above that the THEN denotes the continuation of the rest of the code. It's an "ENDIF" in other languages. Alright, so what do the other words do? Well, the word ." just prints a string. It needs a space between it and the string, and a closing " to indicate the end of the string. The word CR means "carriage return" and moves the cursor/current print position to the next line, scrolling the screen upwards if necessary. Putting It All Together Let's review all the code we have so far: : FRAME ( -- ) \ set up screen and draw frame 1 GMODE \ 32 column text mode 0 1 ASCII - 30 HCHAR 23 1 ASCII - 30 HCHAR 1 0 ASCII | 22 VCHAR 1 31 ASCII | 22 VCHAR 0 0 ASCII + 1 HCHAR 0 31 ASCII + 1 HCHAR 23 0 ASCII + 1 HCHAR 23 31 ASCII + 1 HCHAR ; 1 VALUE BALL_COL 1 VALUE BALL_ROW 1 VALUE XDIR 1 VALUE YDIR : SET_RC ( -- ) \ set row and column 30 RND 1+ TO BALL_COL 22 RND 1+ TO BALL_ROW ; : ERASE_BALL ( -- ) BALL_ROW BALL_COL 32 1 HCHAR ; : MOVE_BALL ( -- ) XDIR +TO BALL_COL YDIR +TO BALL_ROW BALL_ROW BALL_COL ASCII 0 1 HCHAR ; : HIT_NS? ( -- flag ) \ check hit on top or bottom of screen BALL_ROW 2 < BALL_ROW 21 > OR ; : HIT_EW? \ Hit east or west? BALL_COL 2 < BALL_COL 29 > OR ; : REV_XDIR ( -- ) \ reverse x direction XDIR NEGATE TO XDIR ; : REV_YDIR ( -- ) \ reverse y direction YDIR NEGATE TO YDIR ; : CHECK_DIR ( -- ) HIT_EW? IF REV_XDIR THEN HIT_NS? IF REV_YDIR THEN ; So far, you can probably see that we don't yet have a "program" as such. We just have a collection of words that each do something, but we need to glue them together. So, let's break out the glue: : BOUNCE ( -- ) FRAME SET_RC BEGIN ERASE_BALL MOVE_BALL CHECK_DIR AGAIN ; So, BOUNCE calls FRAME which draws the screen, and then SET_RC which sets our row and column values. Then, we BEGIN a loop. The word BEGIN marks the start of the loop. Then, we call ERASE_BALL, MOVE_BALL and CHECK_DIR. Notice how at this high level the code is quite generic. It's almost like English. It's just words strung together in a sentence: "erase ball, move ball, check direction" Then, we execute AGAIN which runs everything again from the word BEGIN (in reality, it jumps back to ERASE_BALL; BEGIN is just a marker to show where it jumps back to). So we have this in our main loop: "erase ball, move ball, check direction, do it again". It's English. Well factored code at the high-level will read like English. Sure, it's not so nice at the low level with all the stack management and stuff going on, but (and this is a big one) you tested all those words "on the way up". You know they work. No need to re-visit them. Your higher level words use the lower level words, and you can keep building your code up in this way. Words stand on the shoulders of other words. It's a LOT more sophisticated than line numbers, so it takes more practice, but once you've got it you won't want to do line numbers again. If you type the complete program in as shown and type BOUNCE you will see the program run. However, there are two problems: It's too fast. You can't really see anything; There's no way to exit. Let's fix that: : DELAY ( n -- ) 0 DO LOOP ; : BOUNCE ( -- ) \ top-level code FRAME SET_RC BEGIN ERASE_BALL MOVE_BALL CHECK_DIR 100 DELAY 0 JOYST 1 = UNTIL ; So, we've introduced a delay word which uses an empty loop just to spin the wheels for a while (more on DO...LOOP in a further article - hopefully someone else will write it! - it's generic; not specific to TurboForth) and we've changed BOUNCE as follows: We now read the first joystick (unit number 0). JOYST pushes a value on the stack according to what the joystick is doing. The only value we're currently interested in is 1, which means the fire button has been pressed. So: We push 0 onto the stack. JOYST uses it to read joystick 0 and pushes the result; We push the number 1 onto the stack; The word = ("equal?") tests the value that JOYST pushed against the 1 that we pushed. If they are equal then "=" will push a true else it will push a false; UNTIL consumes the number that "=" pushed. If it is TRUE then execution is allowed to continue past the UNTIL word, otherwise it loops back to begin. So, our code will loop back to the associated BEGIN word UNTIL the fire button is pressed. There's no code after the UNTIL so everything just stops. You can see that the program is not really a program until we get to the word BOUNCE. That's where a bunch of related, but unconnected words come together to make a program, yet BOUNCE is just another word that we've added to the system. This is how programs are grown in Forth. Of course, it's possible to be more sophisticated (where words leave values on the stack for other words to consume). We haven't done that much here. There is a bit of that going on in CHECK_DIR though. Well, this turned out to be a LOT longer than I was planning. If you stuck with me to the end then I'm grateful. The whole program, in it's finished form which you can cut and paste into Classic99: : FRAME ( -- ) \ set up screen and draw frame 1 GMODE \ 32 column text mode 0 1 ASCII - 30 HCHAR 23 1 ASCII - 30 HCHAR 1 0 ASCII | 22 VCHAR 1 31 ASCII | 22 VCHAR 0 0 ASCII + 1 HCHAR 0 31 ASCII + 1 HCHAR 23 0 ASCII + 1 HCHAR 23 31 ASCII + 1 HCHAR ; 1 VALUE BALL_COL 1 VALUE BALL_ROW 1 VALUE XDIR 1 VALUE YDIR : SET_RC ( -- ) \ set row and column 30 RND 1+ TO BALL_COL 22 RND 1+ TO BALL_ROW ; : ERASE_BALL ( -- ) \ erase ball from screen BALL_ROW BALL_COL 32 1 HCHAR ; : MOVE_BALL ( -- ) \ update ball position and draw it XDIR +TO BALL_COL YDIR +TO BALL_ROW BALL_ROW BALL_COL ASCII 0 1 HCHAR ; : HIT_NS? ( -- flag ) \ hit top or bottom of screen? BALL_ROW 2 < BALL_ROW 21 > OR ; : HIT_EW? \ Hit east or west? BALL_COL 2 < BALL_COL 29 > OR ; : REV_XDIR ( -- ) \ reverse x direction XDIR NEGATE TO XDIR ; : REV_YDIR ( -- ) \ reverse y direction YDIR NEGATE TO YDIR ; : CHECK_DIR ( -- ) \ reverse direction if hit screen edge HIT_EW? IF REV_XDIR THEN HIT_NS? IF REV_YDIR THEN ; : DELAY ( n -- ) 0 DO LOOP ; : BOUNCE ( -- ) \ top-level word FRAME SET_RC BEGIN ERASE_BALL MOVE_BALL CHECK_DIR 100 DELAY 0 JOYST 1 = UNTIL ; References: HCHAR - http://turboforth.net/lang_ref/view_word.asp?ID=220 VCHAR - http://turboforth.net/lang_ref/view_word.asp?id=232 < - http://turboforth.net/lang_ref/view_word.asp?ID=50 > - http://turboforth.net/lang_ref/view_word.asp?ID=54 = - http://turboforth.net/lang_ref/view_word.asp?ID=53 BEGIN - http://turboforth.net/lang_ref/view_word.asp?ID=72 AGAIN - http://turboforth.net/lang_ref/view_word.asp?ID=71 UNTIL - http://turboforth.net/lang_ref/view_word.asp?ID=89 OR - http://turboforth.net/lang_ref/view_word.asp?ID=95 ASCII - http://turboforth.net/lang_ref/view_word.asp?ID=210 VALUE - http://turboforth.net/lang_ref/view_word.asp?ID=168 TO - http://turboforth.net/lang_ref/view_word.asp?id=167 +TO - http://turboforth.net/lang_ref/view_word.asp?id=152 I hope you enjoyed learning some Forth.
  9. Local Variables for the Common Man I wrote a local variables library for TurboForth some years back. It was/is quite sophisticated; Forth words could have their own private, named variables. Nice. Just recently I find I'm interested in writing less code, not more. I find I'm more interested in what code I can do *without* rather than the code I need. This leads to very interesting thought-exercises. It is very interesting to strip code away and arrive at the simplest code you can come up with that still gets the job done. With that in mind, I recently took another look at local variables. For some folk, local variables in Forth are an anathema. I disagree. They reduce stack "juggling", or "stack traffic" where you are just juggling items on the stack to get them into the order you need them in. *Not* spending CPU cycles on juggling is getting more useful work done. Having named local variables in Forth (i.e. local variables that you can give any name to) is very nice, but we can really live without them. In assembly language on the TMS9900, we have 16 global "variables" - the registers. They are named R0 to R15. If we BLWP into a subroutine in a new workspace, we have 16 local variables, also called R0 to R15. The names are fixed, and we seem to get along with them just fine. So why not just do the same with local variables? With that in mind, I thought I would write something to be as economical as possible. I was very pleased with all the code that I *hadn't* written, so I thought I would share what I haven't written here. :-) The first problem to solve is where to put the local variables. We can't put them on the Forth data stack, because they would get in the way of other data that words are pushing/pulling to/from the stack. Imagine this word: : A ( -- ) B C D E ; Imagine that all of the words B C D and E use local variables. Furthermore, these words may internally call other words that also use local variables - maybe B calls Y and Y uses locals, and Y calls Z and Z uses locals. We need a locals stack. Well, a stack is just an area of memory with a pointer that points to the top of the stack: $ff00 value lsp \ locals stack pointer So, here's a VALUE (a type of variable) called 'lsp' (locals stack pointer). We're going to place our locals stack at >FF00 at the end of RAM. Now we need some words that can store values on the data stack. Let's implement three local variables, A, B and C. What are we going to call these words? Well, for storing data in the variables (that is, taking something off the stack and storing it in a local variable) how about >a >b and >c? The arrow before the variable name shows something "going into" the variable. It's a picto-gram. Similarly, for reading from a local variable, (reading from the variable and pushing onto the stack) how about a> b> and c>? The arrow shows something leaving the variable. Looks pretty good to me. So, each word that uses local variables can have three local variables, a,b, and c. That's 6 bytes. +-------+ lsp --> | A | 2 bytes +-------+ | B | 2 bytes +-------+ | C | 2 bytes +-------+ As can be seen, the locals stack pointer (lsp) is pointing to the top of the locals stack. So local variable A will be stored at the address in lsp, local variable B at lsp+2, and local variable C at lsp+6. Simple. Here's the code for writing to the local variables. Note the stack signatures. : >a ( n -- ) lsp ! ; : >b ( n -- ) lsp 2+ ! ; : >c ( n -- ) lsp 4 + ! ; And here's the code for reading from the local variables. Again, note stack signatures. : a> ( -- n ) lsp @ ; : b> ( -- n ) lsp 2+ @ ; : c> ( -- n ) lsp 4 + @ ; Now we need a word to make some space on the locals stack. Again, I'll use a pictogram: : lsp-> ( -- ) 6 +to lsp ; Here, the -> is pointing "upwards" on an imaginary number line, indicating that the word increases the lsp. And here's a word to decrease the local stack pointer: : <-lsp ( -- ) -6 +to lsp ; We're nearly done. All we need to do now is have some method of using the local variables in a Forth word. After some experimenting, the simplest approach I could come up with was to have a new word for : (which is used to create new words) that indicates that we want to create a new word, but with the special property of having access to local variables. For this, I chose :: (two colons). So instead of: : fred ( -- ) some clever code here ; We have: :: fred ( -- ) some clever code here ;; Both are identical, but the word created by :: has access to local variables. Here's the code: : :: : compile lsp-> ; That actually looks quite confusing, so let's break it down: The first colon means "hey, here comes a new word". The double colon is the name of the new word, so we have "hey, here comes a new word called ::" The third colon just includes the behaviour of : *in* the new word! So we have "hey, here comes a new word called :: and I want it do the same thing as : does, thanks." The "compile lsp->" part will ensure that when :: runs (when a new word with locals is being created) a reference to our lsp-> word will be compiled into *that* word (the word that is bing created). Hence, the locals stack will move down memory, and the word will get its own space for its locals at run-time. Finally, we need to terminate the definition, just like ; in a "regular" word. : ;; compile <-lsp [compile] ; ; immediate Again, we use : to create a new word called ;; and this word will compile a reference to <-lsp into the word under creation, thus re-claiming the locals stack space that the word will use at runtime. We then want the word to run the normal ; action to complete the word compilation. Well, ; is an immediate word so we use [compile] to override this behaviour. Then we terminate the ;; itself with ; and we make it immediate, so that it matches the behaviour of ; And voila. We're done. Look how much code it isn't: $ff00 value lsp \ locals stack pointer : >a ( n -- ) lsp ! ; : >b ( n -- ) lsp 2+ ! ; : >c ( n -- ) lsp 4 + ! ; : a> ( -- n ) lsp @ ; : b> ( -- n ) lsp 2+ @ ; : c> ( -- n ) lsp 4 + @ ; : lsp-> ( -- ) 6 +to lsp ; : <-lsp ( -- ) -6 +to lsp ; : :: : compile lsp-> ; : ;; compile <-lsp [compile] ; ; immediate We've just added the ability for Forth words to have true, stacked access to local variables, and it took us 188 bytes! Let's test it and see if it works: :: test2 ( n1 n2 n3 -- ) 3 * >c 3 * >b 3 * >a ." Test 2:" a> . b> . c> . cr ;; :: test1 ( n1 n2 n3 -- ) cr 2* >c 2* >b 2* >a a> b> c> test2 ." Test 1:" a> . b> . c> . cr ;; 1 2 3 test1 If you run this, you get the following output: Test 2: 6 12 18 Test 1: 2 4 6 Explanation of the code: We put 1 2 3 on the stack. Then we call test1. Test1 multiples the top of the stack (n3 in the stack signature) by 2, and stores it in local variable c. In doing so, it is removed from the stack. The next item on the stack (2) is multiplied by 2, and stored in b. Then the last item on the stack (1) is multipled by 2, and stored in a. We then get those stored values out of the local variables and back on to the stack, and call test2. Test2 does a similar thing: Takes the values off the stack, multiolying them by 3 and storing them in *its* local variables. Then it displays them. Then, control is returned to test1 just after the call to test2. Now, the local variables that were in test2 have gone, and the local variables that are in test1 are "back in scope" and we prove that by displaying them. Hence we have proved that we can nest calls to words to contain their own local variables and they work as expected and don't interfere with each other. And all in 188 bytes. Enjoy your Forth!
  10. Hello everyone, I've made a series of 4 YouTube videos describing in detail the conceptual work, and the creation of words to implement an ANTIC disassembler tool in FORTH to compliment the ANTIC assembler that I wrote. This basically demonstrates how FORTH can quickly be used to make useful tools that can be intermingled with the development of programs in FORTH so that you don't have to load entire other programs to get stuff done, but rather just flow from one vocabulary of words to the next. Let me know what you guys, think. -Thom
  11. We continue with decompiling Dealer Demo at $175D, seeing -TRAILING, (.") (PDOTQ), and then a handful of words leading to the word ERROR which decompiles incorrectly. Looking closely, we see that the .WORD PDOTQ precedes strings in the listing, which are represented as a count, followed by the string contents. The code to decompile such a string manually is easy to implement, since we built most of the infrastructure already to decompile Forth name fields, namely: sub cstr_buf { my ($buff, $addr, $size) = @_; my $count = unpack "C", substr($buff, 0, 1); my $string = get_string(substr($buff, 1, $count)); $string = sprintf "%s.BYTE %d,%s", get_label($addr), $count, $string; $count += 1; multi_buf($buff, $addr, $count, $string); $count; } sub cstr { my ($buff, $addr, $size) = read_img(@_); cstr_buf($buff, $addr, $size); } To decompile automatically, we can insert this snippet into forth_buf: if (get_cstrq($val)) { $i += cstr_buf(substr($buff, $i), $addr + $i, $size - $i); } where get_cstrq is: sub get_cstrq { return $_[0] == 0x179c; # PDOTQ } We can apply this to the ERROR word to test that the code works as advertised, e.g. invoking dealerdemo.pl 1a1c yields: 1A1C: 9C 17 .WORD PDOTQ 1A1E: 04 20 20 .BYTE 4,' ? ' 1A21: 3F 20 Let's keep decompiling up through the word FORTH, which has .WORD DODOE, which we discussed last time, and then up through ABORT. Among these words, what differences do we see? EXPECT is implemented significantly differently. The Dealer Demo version is much shorter and simpler than the fig-Forth assembly version. The fig-Forth version has extra code to handle back spaces and carriage returns which are done elsewhere in the Dealer Demo kernel. The null word (literally ascii 0), is largely the same, except it uses BSCR 1 - AND instead of 0 BSCR U/ DROP. The fig-Forth screen listing uses 7 AND unconditionally and has BSCR (blocks per screen) equal to 8, so it more closely follows the Dealer Demo listing. However, in the Dealer Demo, BSCR is one, so these gymnastics to figure out where to read the character from isn't really needed. The word UPPER is dropped from Dealer Demo. This kernel (as are all Atari Forth kernels) is case sensitive so it isn't used. ERROR is modified slightly before calling QUIT. Instead of always leaving IN and BLK on the data stack, we omit IN if reading from disk. Since QUIT doesn't use this data, this presumably is left for debugging reasons. ABORT and QUIT use slightly different strings than the fig-Forth listing. ABORT ends with SEMIS, which isn't really needed since QUIT doesn't return. ABORT also calls some future word at $863A instead of CR, probably to run some Dealer Demo specific initialization. Calling Invoking -refs in our tool shows CREAT, ERROR, WORD, ABORT and QUIT forward references can now be fixed up. CREATE was the missing word used in colon and constant definitions, so we now have largely filled in all the words that implement compilation. I think that's enough for today. Our decompilation tool is now complete, we just need to keep applying it until we've cranked through the rest of the disk. The next post (or maybe two) should complete the kernel (which ends at byte $259f), and the post after that will describe the assembler (which ends at $2be4). dd9.zip
  12. Forth: The Cart Before the Horse (#5) This is one is going to be brief. If you've read any of the Forth primers, or any of the Forth proclamations that I and others make here on Atariage from time-to-time, you'll no doubt have read about how versatile and configurable the language is. We're going to have a very brief look at that today. But it won't be the War And Peace tome that I wrote yesterday. Brian Fox recently wrote some fascinating code for Camel99 that gives the language a more Basic-like syntax. As you probably know, in Forth, arguments and parameters to words (functions) come *before* the word/function that you want to call. This is because words/functions take their data, and put their data on the stack, so the stack has to be loaded before the word is called: TI BASIC: CALL HCHAR(ROW,COLUMN,CHAR,REPEATS) Forth: ROW COLUMN CHAR REPEATS HCHAR This tends to put people off when they look at Forth. It just looks like gobbledy-gook; at least until you understand that ROW and COLUMN etc are going on the stack, and HCHAR removes them. However, Forth is supposedly "the most flexible language of them all", "ultra malleable, "if you don't like it you can change it" blah blah blah. So, why don't we put our money where our mouth is and prove it? Well alrighty then! Inspired by Brian's look at HCHAR and VCHAR I thought it might be fun to demonstrate how the language can be changed to suit your preferences. There are some restrictions, sure, but I think you'll be impressed. We're going to change Forth's HCHAR and VCHAR into TI BASIC's HCHAR and VCHAR, where the arguments come after the word. So, again, let's recap: TI BASIC: CALL HCHAR(ROW,COLUMN,CHAR,REPEATS) Forth: ROW COLUMN CHAR REPEATS HCHAR We're going to end up with: CALL HCHAR( ROW COLUMN CHAR REPEATS ) Furthermore, we want it to be sophisticated enough such that the parameters can be numbers (called literals in Forth parlance) or calls to other words, or complex Forth expressions that compute a value etc. What might shock you is how much code is NOT required to do this. I give you: : CALL ( -- ) ; IMMEDIATE \ do absolutely nothing : HCHAR( ASCII ) WORD EVALUATE STATE @ IF COMPILE HCHAR ELSE HCHAR THEN ; IMMEDIATE : VCHAR( ASCII ) WORD EVALUATE STATE @ IF COMPILE VCHAR ELSE VCHAR THEN ; IMMEDIATE Now, you can type this directly on the command line: PAGE CALL HCHAR( 10 10 42 10 ) CALL VCHAR( 10 10 42 10 ) And behold the awesomeness. Note the spaces: The space between the open parenthesis of HCHAR( and VCHAR( is essential. The spaces between the parameters are just normal for Forth (and actually looks much nicer than using commas). The space before the final closing parenthesis is also required. You just changed Forth to be more like BASIC. You don't have to have numbers in the parameter list. They can be words or expressions: 10 CONSTANT TEN 42 CONSTANT FORTY-TWO CALL HCHAR( TEN TEN FORTY-TWO TEN TEN + ) (That last phrase: TEN TEN + puts 10 on the stack, then another 10 on the stack, then + ("add") removes them and replaces them with their sum, thus leaving the repeat count for HCHAR) So how does it work? Let's look at CALL first. CALL does nothing. It's only job is to be there to make those more familiar with BASIC happy. It has no code in it; it's empty. Furthermore, it's what is known as an IMMEDIATE word, meaning that it executes DURING COMPILATION, not during execution. An example: : FRED ( -- ) CR ." I AM FRED" CR ; Type that in. Nothing much happens. The word FRED gets stored in the dictionary ready to be used. Now type FRED and press enter. FRED executes. No big deal. Now, type this: : BOB ( -- ) CR ." BOO! BOB WAS HERE!" CR ; IMMEDIATE Okay, you typed it in. Nothing much happened. Now execute it: type BOB and press enter. Again, no big surprises. Now, try this: : TOM ( -- ) BOB CR ." HELLO! I AM TOM!" CR ; Did you see what happened? While *TOM* was being compiled, BOB got in on the act and ran, rather rudely announcing his presence. So what happens if we run TOM (type TOM and press enter)? HELLO! I AM TOM! Where's BOB? Should BOB not also say BOO!? No. And the reason why is very clever and is the secret sauce that makes Forth so very powerful. Here it is: "Immediate words execute at compile time." That is, immediate words execute when a word is being compiled, *not* when the compiled word is executed! That's possibly a brain-hurting statement. Consider this TI BASIC code: 10 CALL HCHAR(10,10,42,10) Now, when you press enter, the TI BASIC compiler switches on and compiles your code into some internal magic code that will do what you want it to do when you later RUN it. Okay. All normal stuff. But consider this: When the TI BASIC compiler is compiling that line of code, it does so entirely privately. No have no control over what compiler does. Mind your own business, it's nothing to do with you. The compiler privately compiles that code (or doesn't if there's an error), and you are just a bystander. That's not the case in Forth. In Forth, you can use "immediate" words that run when the compiler is compiling. And because they run when the compiler is compiling, you can "hijack" the compiling process, and do something: make a fart sound; say something on the speech synth; load a file; anything you want. You can even compile your own code. Think about that. Code that compiles code. And THAT is what makes Forth so powerful. So, lets get back to TOM and examine what happened. In Forth, the compiler is switched on by : (colon) and switched off by ; (semi-colon): : SOME-WORD <CODE GOES HERE> ; The compiler just walks along the line of text, and when it sees a word it looks for it in its dictionary and if it finds it, it compiles a call (like a GOSUB) to it. Now you can see why spaces are so critical in Forth. They are what separate the words so that they can be found in the dictionary. However, when the compiler is looking for a word, if it finds it, it checks to see if it is immediate or not. If it is not, it just compiles a call/GOSUB to the word. However, if it *is* immediate, it *executes* it, and does not compile it. That means you can put a reference to an immediate word in your definition, and at that point in the compilation process it will call your immediate word, and *you* can do something to the word that is *currently* being compiled, like add some more code to it. When the immediate word ends, the compiler just carries on compiling, totally oblivious to anything you may or may not have done to the word currently being compiled. It's none of its business. It's your business. You are in total control. Thus when TOM was being *compiled* the compiler saw the reference to the word BOB and saw that it was "an immediate word" and so it executed BOB, and BOB did it's thing (in this case, writing a cheeky message to the screen) and then carried on with the compiling. Now you understand why, when TOM was *executed*, there was no message from BOB. BOB did it's thing while TOM was being *compiled*. Yes. In Forth, there are two distinct excecution phases: Run-time: When a word is just plain excecuting, doing its thang; Compile time: When a word is being compiled. And you can do whatever the hell you want in either phase. You might want to go for a little lie down at this point! Now, lets look at HCHAR( and see what it does: : HCHAR( ASCII ) WORD EVALUATE STATE @ IF COMPILE HCHAR ELSE HCHAR THEN ; IMMEDIATE When the compiler sees HCHAR( it sees that it is immediate and so it executes it. The first thing is does is place the ASCII code for a ) (closed parenthesis) on the stack. Then WORD executes. WORD reads the line of text and will stop when it sees the ) character. So, if you typed CALL HCHAR( 1 2 42 4 ) WORD would capture 1 2 42 4 The output of WORD is two numbers: The address and length of the text that it found. This is fed into EVALUATE that simply evaluates the string as if it were a line of code entered at the keyboard. In this case, 1 2 42 4, or TEN TEN 42 TEN etc. are all valid code, so it executes it according to the rules of Forth: If we're compiling (i.e. the compiler was switched on with : (so we're building a word) then it will compile what it sees; If we're not compiling, it will just execute what it sees there and then, just like in BASIC when you enter something without a line number. So, we're using EVALUATE to evaluate the parameters for us between the HCHAR( word and the closing ) character. Note the cheeky use of the open parenthesis in HCHAR( which makes it look like some part of the the syntax of the word, but it isn't: It's just part of the name! And note also the closing parenthesis which again looks like syntax but is in fact nothing more than a marker for WORD to look for to isolate the parameters so that it can feed them into EVALUATE. The magic of Forth. The last bit of HCHAR( is very simple indeed. It just looks to see if we're in compile mode (the variable STATE will be 0 if we're not compiling, and >0 if we are compiling). If we ARE compiling, we compile a call to HCHAR (the original version of HCHAR built into the TurboForth EPROM). See? We're "injecting" code into the definition that is being compiled. However, if we're NOT compiling, we just execute HCHAR right there and then, which uses the parameters that EVALUATE evaluated for us. Thus we can do: CALL HCHAR( 1 2 42 99 ) (i.e. not in a definition, so it will execute immediately, like BASIC code with no line number) Or : LINE ( -- ) CALL HCHAR( 1 2 42 10 ) ; And both will work fine and do what they're supposed/expected to do. So, again, here's what happens when that LINE defintion above is compiled: The compilier sees that CALL is an immediate word, so it runs it. CALL actually does precisely nothing, it compiles nothing and runs nothing. It has 0 impact on run-time speed. It's purely "syntactic sugar" to sweeten things up for BASIC lovers. It's a total sham. You don't need to use it at all. The compiler sees that HCHAR( is immediate so it runs it. HCHAR( temporarily takes over, and reads the input up to the closing parenthesis and evaluates them. Since we're building a definition (LINE) the compiler is ON, so EVALUATE will compile them (by calling a new instance of the compiler and saying "HEY! Compile this! Thanks man!" (How's that for a mind f**k!?). HCHAR( then exits, it's done it's thing. Control now goes back to the compiler. The compiler only sees ; (semi-colon) because the parameters were consumed by WORD and EVALUATE so it completes the definition and we're done. If you were to disassemble the definition of LINE what you would see is this: 1 2 42 10 HCHAR In other words, HCHAR( re-arranged the code so that the parameters went first, then called a reference to the internal (in the EPROM) HCHAR which expects the parameters to be on the stack. The whole HCHAR( definition is nothing more than a trick which allows us to put the parameters *after* HCHAR( but internally it compiles HCHAR after the parameters. And that is the power of Forth. If you don't like: ROW COLUMN CHAR REPEATS HCHAR You can make your own word to give you: CALL HCHAR( ROW COLUMN CHAR REPEATS ) Or any other combination. And there endeth the lesson. This is without a doubt a bit of mind melter when you are new to Forth, so don't worry if you don't understand it all. I just wanted to give you an appreciation of the power and flexibility of Forth. It's not essential to understand this stuff right now. And now a quick demo using our new words. We haven't covered a lot of the code below yet. For now, just sit back and enjoy. : FWD-BOX ( -- ) 30 0 DO 12 0 DO CALL VCHAR( I I I 33 + J + 24 I 2* - ) CALL VCHAR( I 31 I - I 33 + J + 24 I 2* - ) CALL HCHAR( I I I 33 + J + 32 I 2* - ) CALL HCHAR( 23 I - I I 33 + J + 32 I 2* - ) LOOP LOOP ; : REV-BOX ( -- ) 0 29 DO 12 0 DO CALL VCHAR( I I I 33 + J + 24 I 2* - ) CALL VCHAR( I 31 I - I 33 + J + 24 I 2* - ) CALL HCHAR( I I I 33 + J + 32 I 2* - ) CALL HCHAR( 23 I - I I 33 + J + 32 I 2* - ) LOOP -1 +LOOP ; : BOXES ( -- ) \ top-level - run me 1 GMODE 5 0 DO FWD-BOX REV-BOX LOOP 0 GMODE ." Thanks for watching!" CR ; Note the additional spaces in the paremeters so that it's easier to identify each paremeter. References: HCHAR - http://turboforth.net/lang_ref/view_word.asp?ID=220 VCHAR - http://turboforth.net/lang_ref/view_word.asp?ID=232 IMMEDIATE - http://turboforth.net/lang_ref/view_word.asp?ID=163 ASCII - http://turboforth.net/lang_ref/view_word.asp?ID=210 STATE - http://turboforth.net/lang_ref/view_word.asp?ID=189 COMPILE - http://turboforth.net/lang_ref/view_word.asp?ID=156 IF - http://turboforth.net/lang_ref/view_word.asp?ID=81 THEN - http://turboforth.net/lang_ref/view_word.asp?ID=88 ELSE - http://turboforth.net/lang_ref/view_word.asp?id=76 CONSTANT - http://turboforth.net/lang_ref/view_word.asp?ID=157 CR - http://turboforth.net/lang_ref/view_word.asp?ID=129 ." - http://turboforth.net/lang_ref/view_word.asp?ID=206 DO - http://turboforth.net/lang_ref/view_word.asp?ID=75 LOOP - http://turboforth.net/lang_ref/view_word.asp?id=84 +LOOP - http://turboforth.net/lang_ref/view_word.asp?id=69 I - http://turboforth.net/lang_ref/view_word.asp?ID=80 J - http://turboforth.net/lang_ref/view_word.asp?ID=82
  13. I'm going to take a break from fixing disks images for now and instead talk about the language Forth. Forth grew out of the programming work by Charles Moore in the late 1960s. By the late 1970s interest in it was such that a group of enthusiasts banded together to program it for the microcomputers that were then becoming available. They formed the Forth Interest Group (or FIG) and placed several implementations of the language in the public domain. The implementation for the 6502 was done primarily by William Ragsdale, and was complete in 1980, and it is from this implementation it seems all the various Atari versions derived. That 6502 fig-Forth listing can be found at https://archive.org/details/fig_FORTH_6502_Assembly_Source_Listing, and I've cleaned up the OCR to create a more readable listing at https://ksquiggle.neocities.org/ff6502.htm. It was a significantly different language than the more commonly available BASIC, and due to its low cost and better performance it attracted many adherents. Since the code was available on such liberal terms (essentially public domain), many versions of it proliferated from user groups and some companies, and for a short time it was given modest coverage in the Atari-specific magazines such as Analog and Antic. Forth is built around a small (~6k) kernel of core words which manipulate a pair of stacks and a handful of registers. The compiler converts the code to series of addresses which are interpreted by a tiny virtual machine, and the emphasis is placed on building up the code in small routines (called words). Almost all parts of the language can be rewritten if they are not to the programmer's liking, and a clever inline assembler that let's one rewrite timing critical routines. Despite these strengths, the language failed to become especially popular. Large programs implemented using the fig-Forth model could consume all the memory available if care wasn't taken, and the language itself was typically more difficult to learn than the BASIC's of the day. Programmer's who wanted to escape the limitations of BASIC were encouraged to investigate assembler more frequently, or perhaps a BASIC compiler. This wasn't just a problem with Forth, all the languages for the Atari seemed to struggle to attract users. The earliest version of Forth to appear on the Atari was almost certainly the Forth used to implement the Dealer Demo, most likely in 1980. Developed in-house at Atari, it was released to demonstrate the Atari computers capabilities. It later became the more sophisticated "Coin-Op" Forth. Antic Forth and the fig-Forth 1.4S distributed originally by SoftSide magazine all share this later kernel, but at the time the Dealer Demo was released, the Forth kernel in it was not significantly different than the original fig-Forth kernel, and with a copy of the demo disk you could construct a Forth kernel from it with a little bit of sector editing. To show this, I'm going to decompile the Dealer Demo and extract its kernel for comparison with the original fig-Forth listing. That comparison is the goal, but I'm going to spend quite a bit of time developing the tooling to help do this, as we can leverage those tools in the future to examine other programs. Rather than simply drop all the code at once, I'm going to develop it up again like I did with the atr patching tools, hopefully giving some motivation for the choices I made in the code, and giving readers enough context to adapt the code for other purposes.
  14. This is a some of a message stream I just had with Willsy on installing TurboForth. Hope it helps if some one has a problem. From what I have seen it's a worthy product to program in. Installing the 'turboforth' cart in classic99: To run it, start classic99, and from the menu, select Cartridge --> User --> Open Then navigate to the MODS folder in your classic99 installation, then select TurboForthC.bin Then you're ready to rock. The blocks disk will boot from DSK1 when you select TF from the TI-99/4A selection screen. Just for your reference, you can bypass the auto-boot by holding down enter after selecting TurboForth from the cart selection screen. My note: you can also install the turboforthC.bin and turboforthd.bin in the MODS folder then modify the classic99.ini so that the new version of turboforth will then show up in the user carts area on the menu. installing the BLOCKS disk. Firstly (I didn't make it clear in my post above) you don't need to process the blocks file in any way with TI99DIR or any some such program, it's ready to go - just drag it out of the zip file and drop it into the DSK1 folder. Unfortunately, what I didn't mention (sorry) is that the file is in V9T9 format. I put it in this format as V9T9 format is recognized by a lot of other emulators such as V9T9, PC99 and TI994W. So, you need to click on the Disk menu option in Classic99, and from the DSK1 menu, select the menu option .\DSK1\ Then, make sure your emulated DSK1 'drive' is configured as per the following configuration: my note: It's a FIAD file. I made the dumb (on my part) assumption that it was a .dsk image file and kept trying to read it as such. Also, be sure to check 'recognizes v9t9 headers'. His website is turboforth.net If he doesn't already, he said he have all the latest files up shortly. This is well worth a look. If you have done any programming in the latest generation languages like Java this should be an easy pick up. The stack might be the only thing a little odd, but if you have done assembler, you should be familiar with the concept.
  15. Wow! It's been a really long time since I've done much of any significance with the TI99-4A! I have nearly 80 cartridges, many of which are used by my grandkids on a regular basis when they come over. The productivity software/cartridges (TI BASIC, TI Extended BASIC, TI Writer, TI Multiplan, Editor/Assembler, Terminal Emulator II, TI Logo II and TI FORTH) have seen little use except for TI BASIC until very recently. I have often used TI BASIC for simple math problems like figuring trigonometric solutions for various projects around the house because I could fire up the TI quicker than going upstairs to boot up one of the PCs. I might need the hypotenuse of a right triangle to lay out the paint lines on the grass of the volleyball court. Recently, however, after noticing to my delight an unexpected presence on the Internet of TI99ers, I was inspired to pick up a couple of projects I had long ago allowed to languish for 20 odd years! They both had to do with TI FORTH. One was to clean up and make easier to use with an index and anything else I could use to make it better, the TI FORTH Instruction Manual. The other was to finish a FORTH program I had started that was to solve a problem with a unique Social Security Number (SSN), viz., using the digits 1-9 only once (no 0, of course), construct a SSN with the growing number evenly divisible by the position number of the last digit. For example, 123 needs to be evenly divisible by 3 (it is) and 1234 needs to be divisible by 4 (it is not, but 1236 is), etc. I have finished the FORTH problem and am well on my way to polishing up the TI FORTH Instruction Manual. If there is any interest, I will post the FORTH solution (I may do it anyway!). When I am finished with the TI FORTH Instruction Manual, I will post it, as well. Also, I am certainly interested in whether anyone else is doing anything with the original TI FORTH on the 99-4A. Later... ...lee
  16. Here is a short PDF with some information that you might find interesting. Forth Editors.pdf
  17. I got to wondering how much code it would need to implement the BrainFuck language in Forth. Turns out not much: create array 8000 chars allot variable pointer array pointer ! : reset ( -- ) \ zero bf memory and reset pointer array 8000 0 fill array pointer ! ; : peek ( -- ) pointer @ [email protected] ; : poke ( -- ) pointer @ c! ; : > ( -- ) \ increment the pointer pointer @ 1+ pointer ! ; : < ( -- ) \ decrement the pointer pointer @ 1- pointer ! ; : + ( -- ) \ increment the byte at the pointer peek 1+ poke ; : - ( -- ) \ decrement the byte at the pointer peek 1- poke ; : . ( -- ) \ output the byte at the pointer peek emit ; : , ( -- ) \ input a byte and store it in the byte at the pointer pad 3 expect pad 3 number drop poke ; : [ \ ( -- ) \ jump forward past the matching ] if the byte at the pointer is zero [compile] begin compile peek [compile] while ; immediate : ] ( -- ) \ jump backward to the matching [ unless the byte at the pointer is zero [compile] repeat ; immediate That's a complete BrainFuck *compiler*. Most implementations I have seen are interpreters. Here, you feed in BF code using normal colon definitions. Because it's a normal colon definition, what you get out is compiled Forth code. Here's Hello World! in BrainFuck: : hw ( hello world in BrainFuck ) reset + + + + + + + + [ > + + + + [ > + + > + + + > + + + > + < < < < - ] > + > + > - > > + [ < ] < - ] > > . > - - - . + + + + + + + . . + + + . > > . < - . < . + + + . - - - - - - . - - - - - - - - . > > + . > + + . ; To run it, just type hw and press enter. To prove it's compiled Forth, use SEE (in TurboForth, it's block 27 on the accompanying disk): SEE HW And you get: Forth, you gotta love it. Of course, some say Forth is a bit of a BrainFuck, and it is, until the penny drops. Even then, managing the stack is still a puzzle. But it's so powerful .
  • Create New...