Jump to content

Search the Community

Showing results for tags 'fbForth'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • 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
    • Atari Portfolio
  • Classic Consoles
    • Classic Console Discussion
    • ColecoVision / Adam
    • Intellivision / Aquarius
    • Bally Arcade/Astrocade
    • Odyssey 2 / Videopac
    • Vectrex
    • Nintendo Entertainment System (NES) / Famicom
    • Super Nintendo Entertainment System (SNES) / Super Famicom
    • Sega Genesis
    • 3DO Interactive Multiplayer
    • Dreamcast
    • SMS High Score Club
    • TG-16/PC Engine High Score Club
  • Classic Computing
    • Classic Computing Discussion
    • Apple II Computers
    • TI-99/4A Computers
    • Commodore 8-bit Computers
    • Commodore Amiga
    • Tandy Computers
  • Modern Consoles
    • Modern Gaming Discussion
    • Sony Playstation 5
    • Xbox Series S/X
    • Atari VCS (Redirect)
    • Nintendo Switch
    • Microsoft Xbox One
    • Sony PlayStation 4
    • Microsoft Xbox 360
    • Sony Playstation 3
    • Nintendo Wii / Wii U
  • Gaming General
    • Gaming General Discussion
    • Arcade and Pinball
    • Emulation
    • Hardware
    • Prototypes
    • Gaming Publications and Websites
    • International
  • Marketplace
    • Buy, Sell, and Trade
    • Auction Central
    • Wanted
    • Free Games and More
    • User Feedback Forum
  • Community
  • Community
    • Events
    • Show Us Your Collection!
    • Member Blogs
    • High Score Clubs
    • Poll Forum
    • Contests
    • User Groups
    • AtariAge News Discussion
    • User Submitted News
  • Game Programming
    • Homebrew Discussion
    • Programming
    • Hacks
  • Site
    • Announcements
    • Forum Questions and Answers
    • AtariAge Store Discussion
    • Site and Forum Feedback
    • Rarity Guide
    • Archived Forums
  • 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 General
  • Harmony/Melody's CDFJ
  • Harmony/Melody's DPC+
  • Harmony/Melody's BUS
  • Harmony/Melody's CDFJ+
  • 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 Members' Rigs
  • Dirtarians's Trail Runs & Reports
  • Dirtarians's Wrenching
  • Dirtarians's General Discussion
  • The Green Herb's Discussions
  • Robin Gravel's new blog's My blog
  • Robin Gravel's new blog's Games released
  • Robin Gravel's new blog's The Flintstones Comic Strip
  • 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
  • Atari Video Club's Concerto Games
  • Atari Video Club's AVC Games
  • 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
  • The Homebrew Discussion's Topics
  • Hair Club for Men's Bald? BEGONE!
  • Alternate Reality's Topics
  • Board games, card and figure games's Topics
  • please delete's Topics
  • StellaRT's Topics
  • DOS and Vintage PCs's DOS Discussion

Blogs

  • BinaryGoddess' Blog
  • Albert's Blog
  • MegaManFan's Blog
  • Ed Siegler's Blog
  • FireTiger's Blog
  • Atari Rescue Group's Blog
  • EricBall's Tech Projects
  • liquid_sky's Blog
  • Cybernoid's Blog
  • Lost Blog
  • shep's Blog
  • Trey's Blog
  • Boo
  • Kepone's Blog
  • Beware of Kiwi
  • Fun in the beer mines
  • PacManPlus' Blog
  • Atari 8-bit Moria port
  • Tim's Blog
  • Mindfield's Chewy-Centered Blog
  • The Long Dark Teatime of the Soul
  • TP's Blog
  • Adam Sessler's Brutally Honest Blog
  • Shut Up and Play Yer Atari
  • None
  • Atarinvader's Blog
  • Atari 8-bit archiving
  • Brunobits' Blog
  • ATARIeric's Blog
  • wrenchien's Blog
  • Trade-N-Games' Blog
  • wapchimp's Blog
  • Shared Words
  • Bastard's Blog
  • homerwannabee's Blog
  • Haydn Jones' Blog
  • The World According To Yuppicide
  • How I did It
  • Buck's Blog
  • atwwong's Blog
  • 1
  • sandmountainslim's Blog
  • Atari Jaguar Projects + More
  • StanJr's Blog
  • Schmutzpuppe's Blog
  • Bullitt's Blog
  • panda_racer's Blog
  • Inky's Blog
  • Lauren's Place
  • DanBoris' Tech Blog
  • atariauctions' Blog
  • Planet Bob
  • CSIXTY4.com
  • Robin Gravel's Blog
  • lestergame
  • Duke 4ever's Blog
  • Atari Haiku Blog
  • An7ron
  • glitch's Blog
  • Coleco-Atari Era
  • Kenfused's Blog
  • Ralph3's Blog
  • nester's one star gaming
  • Halt and Catch Fire
  • lizard's Blog
  • Laner's Classic Gaming Blog
  • Page 6
  • keilbaca's rants
  • SirWilliam's Blog
  • Birdie3's blog
  • MattG/Snyper2099's Blog
  • madmjennifer's Blog
  • Ablogalypse Now
  • Endless Quest
  • Greenious' Blog
  • wookie's Blog
  • Justclaws' Blog
  • VTAtari's Blog
  • SID CROWE TESTING THE blog softwareeee
  • Dutchman2000's Blog
  • Famicoman's Blog
  • scogey's Blog
  • Retro Gaming Obscuria
  • atarifan49's Blog
  • Chronogamer
  • flavoredthunder's Blog
  • Shernand's Blog
  • Robert M's Blog
  • albaki's Blog
  • BTHOTU's Blog
  • Zach's Projects
  • BuzzTron-451's Blog
  • The Occasional Coder
  • Joystick Lunatic Software on AtariAge
  • Zander's Blog
  • The randomness that is Mr. 8-bit/16-bit.
  • bluetriforce's Blog
  • ubikuberalles' Blog
  • Worm Development Blog
  • Eight Bit's Blog
  • mos6507's Blog
  • phaxda's Blog
  • potatohead's Blog
  • Mountain King's Blog
  • The Southsider
  • The World is Flat?
  • brianwolters' Blog
  • Bidouille's Blog
  • Zybex/Atariware Blog
  • JagDiesel's Palace 2
  • Sega_master's Blog
  • Deep into the Mind Game
  • Bob's Blog
  • Rockin' Kat's Blog
  • Push Me, Pullman
  • (Insert stupid Blog name here)
  • dgob123's INTV Blog
  • Random Terrain's Tetraternarium
  • Odyssey Development Corner
  • Pacmaniax
  • GPD Comics Blog
  • sergiomario's Blog
  • prorobb's Blog
  • Days Atari Events
  • gamester1's Blog
  • Shannon's Blog
  • Mord's Blog
  • liquidcross.com - blog
  • MIPS HEAVY INDUSTRIES
  • MayDay Today
  • javiero's Blog
  • Great Exploitations
  • Monster Angriff's Blog
  • Draikar's Blog
  • Random Acts of Randomness
  • TROGBlog
  • hex65000's Blog
  • Being Of The Importance Of Shallow Musing.
  • daclmi's Blog
  • 2600 in 2006
  • Sayton's Blog
  • For whom it may concern
  • Osbo's Blog
  • ataridude81's Blog
  • Wiesbaden Gaming Lab
  • SpiceWare's Blog
  • The Upward Spiral
  • Web-Frickin'-Log
  • Starosti 8bitového grafika
  • WWW.BUYATARI.TK
  • commodore & atari :)'s Blog
  • Dusk2600's Blog
  • GAMEBOT
  • Lynx 20 years
  • Songbird Productions
  • SpaceInvader's Blog
  • Retro point of view
  • VampyricDreams666's Blog
  • le geek's nonsense
  • Hardcore's Nostalgia
  • 4old-times-sake's Blog
  • shadow460's Blog
  • AtariJr's Blog
  • Memoirs of an X register
  • maximebeauvais' Blog
  • atari2600land's Blog
  • .:maus:.
  • PAM1234's Blog
  • Nabuko's Den
  • Paranoid's Blog
  • Culmins Development's Blog
  • Atari Joe's Flippin' Sweet Blog
  • When Robots Attack
  • Flack's Daily Smack
  • Jboypacman's Blog
  • neonesmaster's Blog
  • Classic Stories
  • Bruce Tomlin's Blog
  • Beetle's Blog
  • 5-11under's Blog
  • EricDeLee's Blog
  • TunnelRunner's Blog
  • jaymz887's Blog
  • fojy-harakiri's Blog
  • Shroo-man's Blog
  • Ataria51's Blog
  • Mr. Pac-Man's Blog
  • JellE's Dwelling
  • Gaming With Rogmeister
  • Pengwin's Blog
  • neotokeo2001's Blog
  • Arcade's Blog
  • R. Jones' Blog
  • payman84ce's Blog
  • Awed Thoughts
  • super mario 64 level editor
  • Christos' Blog
  • atari_collector's Blog
  • imtron's Blog
  • My Vintage Game collection
  • classicgamingguy's Blog
  • HP Atari King of Michigan's Blog
  • Unknown arcade titles from Fighter17
  • Ain't got time for no Jibbajaba
  • Wickeycolumbus' Blog
  • Ramblings of a moron
  • HatNJ's Blog
  • BlogO
  • ELEKTROTECK
  • bf2k+'s Blog
  • ParaJVE's Blog
  • Cody Rushton's blog
  • It's my life!
  • Bakasama's Blog
  • Dennis V's Blog
  • RaRoss' Blog
  • Collecting Demos
  • Dave Neuman's Blog
  • Borntorun's Blog
  • warren798's Blog
  • Tweety's Blog
  • -^CB^-'s Game Reviews
  • seekingarobiejr's Blog
  • revival studios
  • bust3dstr8's Blog
  • Rom Hunter's Blog
  • Shark05's Blog
  • Lord Helmet's Blog
  • ryanez1's Blog
  • kit's Blog
  • Burma Rocks
  • Bubsy Bobcat Fan Blog
  • Habaki's Blog
  • Dan's Road to 2600 nirvana
  • wccw mark's Blog
  • Hornpipe2's Blog
  • Phantom's Blog
  • Piggles' Blog
  • Dino Dash Derby
  • games_player's Blog
  • 1982VideoGames' Blog
  • Cabbage Patch Kids! Lookin' Great!
  • Confessions of an Aging Gamer...
  • theking21083's Blog
  • retrogeek's Blog
  • Liveinabin's scribbles
  • Cimerians' Blog
  • CollectorVision Blog
  • Ransom's Random Posts
  • www.toyratt.com's Blog
  • RonPrice's Blog
  • s0c7's Blog
  • doyman's Blog
  • DJTekid's Blog
  • EG's code blog
  • kiwilove's Blog
  • 8 Bit Addiction
  • Playing With History
  • simonh's Blog
  • Zereox's Blog
  • Draconland
  • chris_lynx1989's Blog
  • Phuzzed's Blog
  • 7800 NZ's Blog
  • Gamera's Reviews: E.T Coming Soon!
  • Iwan´s Irrational!
  • seemo's Blog
  • The Eviscerator Series
  • Noelio's Blog
  • 480peeka's Blog
  • For Next
  • Take 'Em To The Woodshed
  • bankockor Blog
  • Kelp Entertainment
  • 2600 Fun Blogs
  • PinBlog
  • IHATETHEBEARS' BLOG
  • Atari Fan made Documentary
  • Flashjazzcat's Blog
  • THE 1 2 P's Demo/Import/Gaming Blog
  • STGuy1040's Blog
  • enyalives' Blog
  • Mirage1972's Blog
  • blogs_blog_286
  • The Word Of Ogma
  • GC's blog
  • nanobug's monument of geekiness
  • dogcorn's Blog
  • I Can't Think of a Catchy Title
  • please help and share story
  • ivop's Blog
  • what is the chicago basment
  • Cheat Blog
  • zeropolis79's Blog
  • My video game library
  • the.golden.ax's "Oh my Blog"
  • ValuGamer
  • wolfpackmommy's Blog
  • Z80GUY's Blog
  • jwierer's Blog
  • kroogur's Korner
  • Verbal Compost
  • Frizo's Collecting Adventure!
  • Old School Gamer Review
  • ...
  • Rybags' Blog
  • BDW's Blog
  • tweetmemory's Blog
  • toptenmaterial's Blog
  • grafix's Bit Mouse Playhouse
  • S1500's Blog
  • hackerb9's blog
  • EricBall's Tech Projects (PRIVATE)
  • MagitekAngel's Blog
  • I created this second blog on accident and now I can't figure out how to delete it.
  • keilbaca's Blog
  • TestBot4's Blog
  • Old School Gamer Review
  • The Mario Blog
  • GideonsDad's Blog
  • GideonsDad's Blog
  • GideonsDad's Blog
  • Horst's Blog
  • JIMPACK's Blog
  • Blogpocalypse
  • simonl's Blog
  • creeping insanity
  • Sonic R's Blog
  • CebusCapucinis' Blog
  • Syntax Terror Games
  • NCN's Blog
  • A Wandering Shadow's Travels
  • Arjak's Blog
  • 2600Lives' Blog
  • 2600Lives' Blog
  • Kiwi's Blog
  • Stephen's A8 Blog
  • Zero One
  • Troglodyte's Blog
  • Austin's Blog
  • Robert Hurst
  • This Is Reality Control
  • Animan's Blog Of Unusual Objectionalities
  • Devbinks' Blog
  • a1t3r3g0's Blog
  • The 7800 blog
  • 4Ks' Blog
  • carmel_andrews' Blog
  • iratanam's Blog
  • junkmail's RDE&P Blog
  • Lynxman's FlashCard Blog
  • JagMX's Blog
  • The Wreckening
  • roberto's Blog
  • Incagold's Blog
  • lost blog
  • kurtzzzz's Blog
  • Guitarman's Blog
  • Robert @ AtariAge
  • otaku's Blog
  • otaku's Blog
  • revolutionika's Blog
  • thund3r's Blog
  • edweird13's Blog
  • edweird13's Blog
  • That's what she said.
  • Hitachi's Blog
  • The (hopefully) weekly rant
  • Goochman's Marketplace Blog
  • Marc Oberhäuser's Blog
  • Masquane's AtariAge Blog
  • satan165's Dusty Video Game Museum
  • lazyhoboguy's Blog
  • Retail hell (The EB years)
  • Vectrexer's Blog
  • Game Maker to Game Dev
  • Retro Gaming Corporation
  • Hulsie's Blog
  • Tr3vor's Blog
  • Dryfter's Blog
  • Why Are You Even Reading This?
  • Xuel's Blog
  • GamingMagz
  • travelvietnam's Blog
  • pacmanplayer's Blog
  • TheLunarFox's Blog
  • caver's Blog
  • Atari 2600 for sale with 7 games 2 controllers
  • A Ramblin' Man
  • toiletunes' Blog
  • Justin Payne's Blog
  • ebot
  • Markvergeer's Blog
  • GEOMETRY WARS ATARI 2600
  • LEW2600's Blog
  • Pac-Man Vs Puck-Man's Blog
  • Bri's House
  • Les Frères Baudrand's Blog
  • Secure Your E-Commerce Business With ClickSSL.com
  • raskar42
  • The P3 Studio
  • Bydo's Blog
  • defender666's Blog
  • TheSSLstore - SSL certificates Validity
  • Chuplayer's Blog
  • pacman100000's Blog
  • POKEY experiments
  • JPjuice23's Blog
  • Gary Mc's Blog
  • arkade kid's Blog
  • MaXStaR's Blog
  • SUB HUNTER in A8
  • ScumSoft's Blog
  • The Social Gamer
  • Ping. Pong. Ping. Pong.
  • kgenthe's Blog
  • mapleleaves' Blog
  • Dallas' Blog
  • bfg.gamepassion's Blog
  • Esplonky's Blog
  • Fashion Jewellery's Blog
  • Gabriel's Blog
  • CJ's Ramblings
  • Dastari Creel's Blog
  • dobidy's Blog
  • dragging through the retro streets at dawn
  • Please Delete - Created by Accident
  • Nerdbloggers
  • Algus' Blog
  • Jadedrakerider
  • Appliciousblog.com
  • frederick's Blog
  • longleg's Blog
  • Brain droppings...
  • Sandra's blog
  • Bastelbutze
  • polo
  • VectorGamer's Blog
  • Maybe its a Terrible Tragedy
  • Guru Meditation
  • - - - - - -
  • The 12 Turn Program: Board Game Addiction and You
  • Tezz's projects blog
  • chonglily's Blog
  • masseo1's Blog
  • DCUltrapro's Blog
  • Disjaukifa's Blog
  • Vic George 2K3's Blog
  • Whoopdeedoo
  • ge.twik's Blog
  • DJT's High Score Blog [Test]
  • Disjaukifa's Assembly Blog
  • GonzoGamer's Blog
  • MartinP's Blog
  • marshaz's Blog
  • Pandora Jewelry's Blog
  • Blues76's Blog
  • Adam24's AtariAge Blog!
  • w1k's Blog
  • 8-bit-dreams' Blog
  • Computer Help
  • Chris++'s Blog
  • an atari story
  • JDRose
  • raz0red's Blog
  • The Forth Files
  • The Forth Files
  • A.L.L.'s Blog
  • Frankodragon's Blog Stuffs
  • Partyhaus
  • kankan313rd's Blog
  • n8littlefield's Blog
  • joshuawins99's Blog
  • ¡Viva Atari!
  • FujiSkunk's Blog
  • The hunt for the PAL Heavy Sixer
  • Liduario's Blog
  • kakpu's Blog
  • HSC Experience
  • people to fix atari Blog
  • Gronka's Blog
  • Joey Z's Atari Projects
  • cncfreak's Blog
  • Ariana585's Blog
  • 8BitBites.com
  • BrutallyHonestGamer's Blog
  • falcon_'s Blog
  • lushgirl_80's Blog
  • Lynx Links
  • bomberpunk's Blog
  • CorBlog
  • My Ideas/Rants
  • quetch's Blog
  • jamvans game hunting blog
  • CannibalCat's Blog
  • jakeLearns' Blog
  • DSC927's Blog
  • jetset's Blog
  • wibblebibble's Basic Blog
  • retrovideogamecollector's Blog
  • Sonny Rae's Blog
  • The Golden Age Arcade Historian
  • dianefox's Blog
  • DOMnation's Blog
  • segagamer99's Blog
  • RickR's Blog
  • craftsmanMIKE's Blog
  • gorf68's Blog
  • Gnuberubs Sojourn Dev Journal
  • B
  • iesposta's Blog
  • Cool 'n' Crispy: The Blog of Iceberg_Lettuce
  • ahuffman's Blog
  • Bergum's Thoughts Blog
  • marminer's Blog
  • BubsyFan101 n CO's Pile Of Game Picks
  • I like to rant.
  • Cleaning up my 2600
  • AnimaInCorpore's Blog
  • Space Centurion's Blog
  • Coleco Pacman Simulator (CPMS)
  • ianoid's Blog
  • HLO projects
  • Retro Junky Garage
  • Sega Genesis/Mega Drive High Score Club
  • Prixel Derp
  • HuckleCat's Blog
  • AtariVCS101's Blog
  • Tales from the Game Room's Blog
  • VVHQ
  • Antichambre's Blog
  • REMOVED BY LAW AUTHORITY
  • Synthpop Universe
  • Atari 5200 Joystick Controllers
  • Top 10 Atari 2600 Games
  • Is Atari Still Cool?
  • Buying Atari on Ebay
  • matosimi's Blog
  • GadgetUK's Blog
  • The StarrLab
  • Scooter83 aka Atari 8 Bit Game Hunters' Blog
  • Buddpaul's Blog
  • TheGameCollector's Blog
  • Gamming
  • Centurion's Blog
  • GunsRs7's Blog
  • DPYushira's Entertainment Blog
  • JHL's Blog
  • Intellivision Pierce's Blog
  • Manoau2002 Game and Vinyl Blog
  • Diamond in the Rough
  • Linky's Blog
  • flashno1's Blog
  • Atari 2600 Lab
  • jennyjames' Blog
  • scrottie's Blog
  • Draven1087's Blog
  • Omegamatrix's Blog
  • MegaData Manifesto
  • Selling Atari on Ebay.
  • Unfinished Bitness
  • TI-99/4A Stuff
  • eshu's blog
  • LaXDragon's Blog
  • GozAtari8
  • Bio's Blog of Randomness
  • Out of the Pack
  • Paul Lay's Blog
  • Make Atari 2600 games w/o programming!
  • Rudy's Blog
  • kenjennings' Blog
  • The Game Pit
  • PShunny's Blog
  • Ezeray's Blog
  • Atari 2600 game maps
  • Crazy Climber Metal
  • Keith Makes Games
  • A virtual waste of virtual space
  • TheHoboInYourRoom's Blog
  • Msp Cheats Tips And Techniques To Create You A Better Gamer
  • Tursi's Blog
  • F#READY's Blog
  • bow830
  • Gernots A500 game reviews
  • Byte's Blog
  • The Atari Strikes Back
  • no code, only games now
  • wongojack's Blog
  • Lost Dragon's Blog
  • Musings of the White Lion
  • The Usotsuki Crunch
  • Gunstar's Blogs
  • Lesles12's Blog
  • Atari Randomness
  • OLD CS1's Blog
  • waterMELONE's Blog
  • Flickertail's Blog
  • Dexter's Laboratory Blog
  • ATASCI's Blog
  • ATASCI's Blog
  • --- Ω ---'s Blog
  • mourifay's Blog
  • Zsuttle's gaming adventures
  • Doctor Clu's Space Shows
  • TWO PRINTERS ONE ADAM
  • Atari Jaguar Game Mascots
  • Learning fbForth 2.0
  • splendidnut's Blog
  • The Atari Jaguar Game by Game Podcast
  • Syzygy's Story Blog
  • Atarian Video Game Reviews
  • Caféman's Blog
  • IainGrimm's Blog
  • player1"NOT"ready's Blog
  • Alexandru George's Blog
  • BraggProductions' Blog
  • XDK.development present Microsoft Xbox One Development
  • Song I Wake Up To
  • Jeffrey.Shamblin's Blog
  • Important people who shaped the TI 99/4A World
  • My blog of stuff and things
  • David Vella's Blog
  • Osgeld's Blog
  • CyranoJ's ST Ports
  • InnovaX5's Blog
  • Star_Wars_Collector
  • Alp's Art Blog
  • Excali-blog
  • STGraves' Blog
  • Retro VGS Coleco Chameleon Timeline
  • Geoff Retro Gamer
  • Geoff1980's Blog
  • Coleco Mini
  • Coleco Mini
  • 7399MGM's Blog
  • 7399MGM's Blog
  • doubledragon77's Blog
  • Ballblogɀer
  • pitfallharry95's Blog
  • BawesomeBurf's Blog
  • Fultonbot's Atari Blog
  • Dmitry's Blog
  • Kaug Neatos Crash Bandicoot Bandwagon
  • lexmar482's Blog
  • vegathechosen's Blog
  • Atari 2600JS
  • Doctor Clu's Dissertations
  • schmitzi's Blog
  • BNE Jeff's Blog
  • AverageSoftware's Development Blog
  • FireBlaze's Blog
  • Atarimuseum.nl
  • Vorticon's Blog
  • TurkVanGogH GameZ's Blog
  • bow830's Blog
  • Arcade Attack - Retro Gaming Blog
  • MrRetroGamer's Blog
  • GG's Game Dev, Homebrew Review, Etc. Log
  • dazza's arcade machine games
  • Alcor450's Blog
  • The Outback
  • -^CroSBow^-'s Hardware Videos
  • Captain's Blog
  • Memoirs of a Novelty Account
  • newcoleco's Random Blog
  • Second-Hand Shop
  • Doctor Clu's BBS Trotter
  • Lunar eclipse of the mind
  • simon2014's Blog
  • PhilipTheWhovian's Blog
  • Troff the Shelf
  • jacobus Indev
  • Pac & Pal for the Atari 2600 fan project
  • drawscreen then reset
  • Retrogaming Ramblings
  • G-type's Blog
  • Blog o' Buttons
  • DarQ Massacres' Atari 2600 collection
  • FireStarW's Blog
  • Bobbety_F's Blog
  • Rose-Tinted Recollections
  • Young Guy Experiencing Atari
  • Gray Defender's Blog
  • atasciiview
  • 2600 games worse then E.t
  • ZippyRedPlumber's Blog
  • game_escape's Blog
  • Jackel192's Blog
  • The UAV Blog
  • MykGerard
  • OS9Dude's Blog
  • FPGA video game console
  • darryl1970's Blog
  • Funkmaster V's Gettin' Hip with tha Atari 7800
  • AtariMI1978's Blog
  • AtariMI1978's Blog
  • vidak's Blog
  • 8-bit Computer System Colors in Food Coloring
  • WebSiteRing
  • The Best Assembly Computer
  • As time goes by ...
  • Atari 2600 Collection Bulk Box/ Cartridge Sale
  • T.R.A.S.H Blog
  • goodlasers' Blog
  • GauntletKing2878's Blog
  • My Inner Geek
  • A Raccoon's Retrocade Romp - AA Edition
  • homeboy's Blog
  • ThatAtomCat's Blog
  • Hawk's Blog
  • Bryan's Random Stuff
  • Developing Atari Programs on the Atari 800
  • Eltigro's Blog
  • Memories Limited to 640KB
  • my journey to completing the entire Atari libaray
  • Roblox
  • Question for Homebrew publishers
  • zilog_z80a's Blog
  • Return of the Bobcat
  • deepthaw's Blog
  • Little bit of this and little bit of that
  • Shannon's Blog
  • DoctorSpuds Reviews Things
  • Atari Portfolio Page On Facebook
  • azure's Blog
  • The Atari Kid
  • Alien Isolation Blog
  • Atari_Ace's Blog
  • AtariAdventure's Blog
  • AtariCrypt
  • acsabo's Blog
  • Bioshock Text adventure
  • AtariAdventure Reviews
  • Infinite Warfare Specialist
  • Karl's Blog
  • Bjorkinator's Babbles
  • DZ-Jay's Random Blog
  • CX40Hero's Blog
  • Heroes & Shadows Dev Blog
  • Empty
  • GoldLeader's Blog
  • Adventures in CC65
  • CS2X C# on Atari
  • pboland's Blog
  • Matts's Blog
  • orrko8791's Blog
  • orrko8791's Blog
  • Revontuli's Blog
  • Not Steve's Blog
  • Not Steve's Blog
  • SPACE ROANOKE
  • My life
  • skycop's Blog
  • cessnaace's Blog
  • Omegasupreme's Blog
  • Atari 2600 A/V Mods Wiki
  • Mike Harris' Blog
  • Skwrl63's Blog
  • sometimes99er
  • Mallard Games Development Blog
  • Regaining an Obsession
  • Psi-5
  • The Atari Journals
  • Herovania
  • TBA
  • Bluejay Records Co.
  • Running On Fumes
  • Mozartkügel's Midnight Retro Development
  • Alcadon
  • baktra
  • Flojomojo's Simple Mind
  • MarkO
  • Lazydead's Loose Ends
  • OldSchoolRetroGamer's Bloggy Nonsense
  • Magmavision After Dark
  • My Homebrew Devlog
  • BUBSY Blogs [blank]
  • Too young for Atari, too old for XBox
  • KC-ACE Blog
  • Brown Altitude Bar
  • Bubsy TV Pilot Wiki
  • Poltergeist
  • Projektstunde
  • bluejay's corner of random shit
  • SpornyKun
  • alex_79's Blog
  • Atari Label Reproduction/ Relabeling
  • Ephemeral
  • My opinion and story about Atari 2600
  • Sony PlayStation 5/PS5™ Development Kit (Dev Kit) for SALE
  • Delete
  • Superkitten
  • Doublediwn
  • Reindeer Flotilla
  • Intellivision hacks (.cfg files)
  • My Experience Learning 68k Assembly
  • My Atari Projects
  • Writing is hard
  • My Atari 2600 Collection
  • Jodi C. Kirby's blog
  • Power outage a few days ago
  • Sony PlayStation 5/PS5™ Development Kit (Dev Kit) for SALE
  • xNeoGeo1982Blogx
  • The Ivory Tower Collections 7800s
  • Incognito Atari 800 step by step pictorial install tutorial/guide including ATR swap button mod
  • Cree's Stories
  • Testing
  • NeonPeon's (Mark W's) Adventures in programming for Vectrex
  • Stories from the -: ITC :-
  • Gameboy & dress up games
  • BRP's random dev journaling
  • My PC-Engine/TurboGrafx-16 Projects
  • Ivory Tower Technical Notes
  • Programming a game..
  • Games People Play
  • Atari 8-bit Memories, Ideas, and Active Projects
  • WEATHER REPORT
  • Biff's Blasts
  • Programming Journey
  • CREE BENNET DOESN'T CARE
  • Mark W Plays Old Games on a Thursday
  • 35 Years, 9 Months and 16 Days in the Life Of...
  • IntellivisionRevolution's Blog
  • Atari BBS Gurus's News
  • On Duty's Blog
  • The official Robin Gravel's club's Archive
  • Bowling's Blog
  • Lawnmover's Blog
  • Null's null
  • Null's Blog
  • KC-ACE Reboot's KC-ACE Reboot Blog
  • Wizzy's Concept and Theme
  • Wizzy's Form
  • Wizzy's Moodboard
  • Wizzy's Space
  • Wizzy's Magical objects
  • Wizzy's Progress
  • Wizzy's At home
  • Wizzy's Halloween
  • Wizzy's Equipping
  • Wizzy's Mentor
  • Wizzy's World
  • Wizzy's Trials
  • Wizzy's Characters
  • Alternate Reality's Blog

Calendars

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

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Website


Facebook


Twitter


Instagram


YouTube


eBay


GitHub


Custom Status


Location


Interests


Currently Playing


Playing Next

Found 11 results

  1. The following questions in another topic prompted this post dedicated to speech in fbForth 2.x: Both speech and sound are serviced by the fbForth 2.x ISR (Interrupt Service Routine) via an up-to-three-address branch stack that is populated when the ISR is called by the console ISR through the ISR hook at >83C4. [fbForth sound words do not use the console ISR’s sound player.] The branch stack will have entries only if speech and/or sound table #1 (immediate or sequential sounds) and/or sound table #2 (immediate playing over muted sound table #1) are awaiting service. Though sound processing is not part of this topic, for the sake of completeness, I will mention that multiple sound tables can be added to the sound stack to be processed sequentially. I mention this here because I did not provide for a speech stack, which could be a useful addition to a future version of fbForth. Currently, if you want more than one block of speech to be spoken sequentially, you must use TALKING? to check whether the Speech Synthesizer is idle. Otherwise, the second block of speech will immediately cancel what is being spoken of the previous block. Because the ISR services speech, further program processing is interrupted only very briefly to process the next bit of speech. The speech synthesizer itself does not suspend processing while it is actually speaking. Here is some example code that illustrates what actually happens: HEX \ Speech Synthesizer strings--- \ "Hello" : HELLO ( -- addr n ) HERE 351A , 1 ; \ "Do not be so negative" : NONEG ( -- addr n ) DATA[ 2480 4AAB 1A42 6153 48DC ]DATA ; DECIMAL : RUN HELLO SAY BEGIN TALKING? 0= UNTIL \ wait until done saying "hello" NONEG SAY \ start saying, "do not be so negative" \ print 200 numbers 200 0 DO I . LOOP ; RUN You will notice that you do not hear speech until nearly 100 numbers have been displayed, even though speech was started before the number-printing loop. What is clear, however, is that processing continues during speech synthesizer processing. Obviously, the loop containing TALKING? does suspend further speech processing until “hello” is spoken. This was done to prevent the next phrase from stepping on “hello”. Just remove that loop to see what I mean. What is interesting (read, “I don’t have a clue why”) is that printing starts before even the start of “hello” is heard, which means that the TALKING? loop already finished and that hearing what the speech synthesizer sends to the audio channel has a significant delay. This was done with Classic99 QI399.063, so I do not know whether this also obtains on real iron because I did not bring a TI-99/4A with me to Florida, but I would expect it to perform similarly. ...lee
  2. This lesson will discuss more of the details of RAM organization, working with the stack and some minimal Forth programming. The 32 KiB expansion RAM on the TI-99/4A is organized as follows in fbForth 2.0: The 8 KiB lower RAM (2000h – 3FFFh) contains four fbForth block buffers, low-level Assembly Language support, system global variables (termed “user variables”) and the return stack. You will notice here that hexadecimal numbers in this discussion (not in actual Forth code!) have a trailing ‘h’. The return stack starts at the top of this space at 3FFEh and grows downward toward the low-level support code, which currently ends at 3A03h. This allows 766 cells for address storage for deeply nested code. Colon ( : ), introduced in the last lesson, makes extensive use of the return stack. Your code can make use of the return stack as well; but, you must be very, very careful when you do, that you do not interfere with the return scheme of fbForth. In a later lesson we will discuss how to safely use the return stack because it certainly can be useful. The 24 KiB upper RAM (A000h – FFFFh) is almost entirely free for your Forth programming pleasure. This is due to the fact that the entire resident dictionary of fbForth 2.0 resides in the 32 KiB ROM of the cartridge. The last word of the resident dictionary is TASK and resides at A000h for reasons that will be explained in a later lesson. The next available address is A00Ch. This is the beginning of the user-definable dictionary. Any words defined after this point are still part of the dictionary and, as a result, become part of the language. This is what makes Forth extensible. The top of memory in the upper 24 KiB area contains the Terminal Input Buffer (TIB) and the base of the parameter stack at FFA0h. This means that all but 108 bytes of the upper 24 KiB area is available for your programming. This, of course, includes the parameter stack, which grows downward toward the dictionary, which grows upward toward the stack. Now is a good time to elaborate on a comment Owen left on the last lesson, viz., verbalizing or pronouncing Forth words. Forth was intended to be a language you could speak. That is pretty much why Forth functions, routines, constants and variables are called “words”. I will try to remember to include the usual pronunciation of standard Forth words as we discuss them. A very good source for such pronunciations is Derick and Becker’s FORTH Encyclopedia: The Complete FORTH Programmer’s Manual, 2nd Edition. The words appear in ASCII order, so they are easy to find. Each of the entries includes the word’s pronunciation. An example from the last lesson is SP! , which is usually pronounced “S-P-store”. The “SP” part happens to refer to the stack pointer, which is why I had said “stack pointer store”. Another example, as Owen mentioned, is “dot-quote” for ." and “quote” for " . Most words’ pronunciations are not difficult to figure out; but, there are a couple of heavily used words that are not obvious. One is @ , which is pronounced “fetch” because it pops an address from the stack and fetches its contents to the stack. Another is ! , which is pronounced “store”. It requires two numbers on the stack: the number to store and the address in which to store it. We will discuss these in greater detail ere long. We turn our attention, now, to working with the stack. As mentioned last time, it operates in a LIFO mode. To show you how it works, we will use . and a new word, .S (pronounced “dot-S” and means “print stack”). .S will non-destructively print the stack contents from the bottom up (left to right), with ‘|’ representing the bottom of the stack. Recall that . pops the top number off the stack and prints it: You will see that the system response of “ok:5” displayed after .S is executed shows the stack to have the same depth as before it was executed. Notice that the last of the five numbers entered is on top of the stack, that it is the first one popped and printed by . and that the system response shows the depth to be one less after each . . The last line demonstrates what happens when you execute a word requiring a number on the stack but with nothing on the stack. The number 11776 (2E00h) printed is significant because the bottom edge of the stack is the start of the TIB and the last thing entered at the terminal (console) was ‘ . ’, which has an ASCII code of 2Eh. A Forth convention when defining or listing words is to show the state of the stack before and after the word executes. The stack effects (also, stack signature) are indicated by showing within parentheses what the word expects on top of the stack before it executes to the left of an em-dash (—) (or two or three dashes [--]) and what it leaves on the stack to the right. Also, the most accessible number is always on the right on either side of ‘--’, which represents execution of the word. For example: ! ( n addr -- ) shows that the stack effects of ! , which requires the storage address addr to be on top of the stack and the number n, which will be stored at addr, below it. The absence of anything to the right of the execution indicator (--) shows that ! leaves nothing on the stack. Let's do a little math with the stack. We will start with the basic four: addition, subtraction, multiplication and division. Here are those definitions with their stack effects: + ( n1 n2 -- sum ) pronounced “plus” - ( n1 n2 -- diff ) pronounced “subtract” * ( n1 n2 -- prod ) pronounced “times” / ( n1 n2 -- quot ) pronounced “divide” Each of these operators requires two numbers on the stack and leaves the result on the stack when it is done. Below are examples of each operation, showing the result printed with . : As you type the above at the terminal, you will see that the operator is after the numbers it operates on. This is an example of postfix notation or RPN (Reverse Polish Notation). You are probably more familiar with infix (algebraic) notation: 1 + 2 = 3 where the operator is between the two numbers it operates on. The postfix nature of Forth is the highest hurdle you will likely need to get over. Words in Forth can certainly be defined in an infix way; but, postfix is more efficient and easier to implement. An interesting bit of history regarding RPN: Reverse Polish Notation implies that there is a Polish Notation, which, of course, there is. Polish logician Jan Łukasiewic (yahn woo-kah-SHEH-vitch) invented prefix notation to simplify a branch of mathematical logic. The operator precedes its two operands in prefix notation. It became known as Polish Notation (PN) due to the nationality of Łukasiewic. Quite naturally, when postfix notation arrived on the scene with the exact opposite form, it became known as Reverse Polish Notation (RPN). At the top of this lesson, we discussed memory organization, stating that virtually all of the available programming memory is one chunk between the top of the parameter stack and the most recently defined word in the dictionary. Each of these locations is readily available with resident fbForth 2.0 words: SP@ ( -- addr ) pronounced “S-P-fetch”; leaves on the stack the address of top of stack HERE ( -- addr ) pronounced “here”; leaves on the stack the address of next available dictionary location The available RAM is the difference between these two addresses. Since the stack is at the higher address, we want to subtract HERE from the top-of-stack address: We can make a couple of useful definitions from this: : SIZE ( -- n ) SP@ HERE - ; : .SIZE ( -- ) SIZE . ." bytes free" ; The first one leaves the size in bytes of free RAM between the top of the stack and HERE . The second prints that number followed by “bytes free”. You may have noticed that I slipped in another word in the definitions above, viz., ( . Pronounced “left paren”, it begins a comment, which is terminated by ‘)’. Comments are ignored by the text interpreter. Obviously, the comments above are not necessary for the definitions to work. You can enter the above definitions without them. They help us to remember what the words do. We will make it a habit to include the stack effects in this way when we actually begin storing our new words in a blocks file a lesson or two hence. We will conclude this lesson by defining one more useful word. CLS is a resident fbForth word that clears the screen but does not move the cursor. To also move the cursor to the top of the display screen, we will define PAGE for which we need another fbForth word that sets the cursor: GOTOXY ( x y -- ) sets the cursor to the x-y coordinates on the stack. The upper left corner of the display screen is at x = 0, y = 0. To show GOTOXY in action, we will place the cursor somewhere in the middle of the screen and print an ‘X’ there: And, now, our definition of PAGE : : PAGE ( -- ) CLS 0 0 GOTOXY ; clears the screen and sets the cursor to the top left corner of the display screen. Here is the screen after the definition and just before execution: and after execution: That’s it for this session. We will do more stack manipulation and programming next time.
  3. 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.
  4. Here is a short PDF with some information that you might find interesting. Forth Editors.pdf
  5. 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
  6. 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.
  7. I am starting this thread to collect various examples of bitmap graphics programming in fbForth 2.0. This first example is a quick-and-dirty joystick drawing program, JDRAW , ported from the program of the same name I wrote four years ago for TI Forth in post #48 of thread, TI FORTH Version 3.0 dated October 20 1982. As I stated then, it is a pretty useless program except as a demo and proof of concept. It uses the CRU mode of JOYST for joystick-only use. There is a three-choice menu accessed with the fire button. The choices are P—Toggle pen up/down [blue pen = pen down; white pen = pen up] D—Toggle draw/erase [ solid pen = draw mode; hollow pen = erase mode] Q—Quit program The joystick moves the pen around the display screen. There is much that could be done to make it more useful. One such thing would be to provide finer control over the pen—reaction to joystick movement is too fast for any useful drawing. Another would probably be to dispense with the menu and use the fire button for pen-up/pen-down. But, that leaves managing draw/erase mode, which would probably require using the JOYST word in keyboard (KSCAN) mode. Anyway, here is the fbForth 2.0 source code for JDRAW : I will add a blocks file, later. For now, you can paste this in Classic99 at the command line of fbForth 2.0. Start the program by typing: JDRAW ...lee
  8. OK...Here is @Willsy's “Hunt the Wumpus” ported to fbForth 2.0: As you can see, it took a bit more than “a few (very minor) changes”! The changes are all documented in the comments at the beginning, which you do not need to load for a working game. [EDIT: Bug fixes in GETROOM , DOMOVE , DOSHOOT and GAMELOOP .] ...lee
  9. In this lesson we will learn a few new arithmetic words, several words for stack manipulation and how to use them all in programming, i.e., defining new words. Before we do much more Forth arithmetic, let’s exercise our brains with some infix-to-postfix and postfix-to-infix conversions. Remember that infix notation is the same as algebraic notation and postfix is the same as RPN. Many of these exercises are based on or taken directly from Brodie’s Starting FORTH. Convert the following infix expressions to their postfix counterparts. Each answer is in the spoiler following the infix expression: 1. a + bc 2. a(b + c) 3. (a - 10b)/3 + c 4. 2a + 5b + (c + d)/3 5. 0.5ab/100 6. (a - b)/c Convert the following postfix expressions to their corresponding infix expressions: 1. a b - a b + / 2. a b 10 * / Now, let’s try to define some words that do calculations, using only the arithmetic operators we have learned to this point. Let’s define words that convert liquid measure in gallons, quarts, pints and fluid ounces to fluid ounces. We want to write out a phrase such as 2 GALLONS 3 QUARTS + 5 CUPS + 25 FLUID OUNCES + to put on the stack the result in fluid ounces. Starting with pints, we can define the next higher volume in terms of the next lower as follows: : FLUID ( -- ) ; a no-op, i.e., do-nothing visual place-holder word. : OUNCES ( floz -- floz ) ; a no-op visual place-holder word that indicates a value in fluid ounces is on the stack and unchanged by OUNCES . : PINTS ( pt -- floz ) 16 * ; converts pints to fluid ounces. : QUARTS ( qt -- floz ) PINTS 2 * ; converts quarts to fluid ounces. : GALLONS ( gal -- floz ) QUARTS 4 * ; converts gallons to fluid ounces. Note that the stack effects are comments in the above definitions for reminding us of each word’s function. You do not need to type them to have a functional definition. We can define the singular forms of the above words, with identical stack effects, in terms of the plural word names above as follows: : OUNCE OUNCES ; : PINT PINTS ; : QUART QUARTS ; : GALLON GALLONS ; These are now synonyms of the words included in each definition. Now we can write such phrases as the following: You can verify with a calculator that each result printed by . is the total liquid measure in fluid ounces of the quantities added before printing. Now, let’s define words to perform the arithmetic in the above six infix-to-postfix exercises. We will name each word as Exn , where n is the exercise number: 1. 2. 3. 4. 5. 6. We can only do integer arithmetic with the Forth we have learned thus far. Two more division operators can help us manage this a little better, viz., MOD (pronounced “mod”) and /MOD (pronounced “slash-mod”): MOD ( n1 n2 — rem ) leaves on the stack the remainder rem from n1/n2. /MOD ( n1 n2 — rem quot ) leaves on the stack the remainder rem and the quotient quot from n1/n2. As we discovered in the exercise definitions above, #4 is very difficult and #6 is impossible without some stack manipulation we haven’t yet learned. Here are some words that will help us to manipulate the stack: DUP ( n — n n ) duplicates the top stack cell. SWAP ( n1 n2 — n2 n1 ) reverses the top two stack cells. OVER ( n1 n2 — n1 n2 n1 ) copies the second cell to the top of the stack. ROT ( n1 n2 n3 — n2 n3 n1 ) rotates the third cell to the top of the stack. DROP ( n — ) drops the top cell from the stack. EX4 can now be defined as Here is a commented version of EX4 to explain a little better how it works. The running contents of the stack are shown in comments as “stack:...” when the stack is changed by a line of code: and EX6 is now tractable as and the commented version to monitor the stack: Let’s try our hand at defining words for these two formulas for converting between Fahrenheit (°F) and Celsius (°C) temperatures: F = 9C/5 + 32 C = 5(F - 32)/9 Let’s define TC>TF to do the Fahrenheit-to-Celsius conversion (formula #1) and TF>TC for the opposite conversion (formula #2). Try it yourself before opening the spoiler below to see one way to do it: : TC>TF : TF>TC Now let’s improve these words to round to the nearest degree using /MOD instead of / so we can work with the remainder of the integer division. We also need to expand the factors 9/5 and 5/9 to 18/10 and 10/18, respectively, so we can halve the divisor and still get an integer: : TC>TF : TF>TC Here are commented versions for clarity: : TC>TF : TF>TC Be sure to try some negative temperatures. Compare the results with a calculator. Anything wrong? The following fbForth 2.0 word will help us craft a better rounding solution: SGN ( n — -1|0|1 ) leaves on the stack the sign (-1 or 1) of n or 0 for n = 0. The symbol ‘|’ in the stack effects means “or” and separates possible results, only one of which will be left on the stack. To get the above temperature-conversion words to round properly in both the positive and negative directions, we need to change the sign of the half-divisor term to match the remainder given by /MOD . Because SGN consumes the number it is testing, we need to DUP it before we hand it off to SGN . All we need to do now is to multiply the half-divisor term by the sign, add the result to the remainder term and divide again. This time we don’t care about the remainder. This quotient will be our rounding term of 1, -1 or 0, which, when added to the previous integer result, will give us our correctly rounded conversion: : TC>TF : TF>TC And commented versions for clarity: : TC>TF : TF>TC That’s all for this session. Please, feel free to ask questions and make suggestions; and certainly, let me know of any mistakes you find.
  10. In post #1 of fbForth—TI Forth with File-based Block I/O , I have updated the fbForth 2.0 Manual (a PDF with today’s date) and the blocks file, FBLOCKS (in a ZIP file with today’s date). The ZIP file also contains two disk images (90KiB and 400KiB) with the updated FBLOCKS file. The cartridge binaries for EPROM, Classic99 and MESS are still current except for FBLOCKS, which you can update from the above ZIP file. ...lee
  11. 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 at cost for $7.70 until 6/20/2023 on Amazon.com. After that, it will be $10.56. 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).
×
×
  • Create New...