![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() Editable LibreOffice version I want to translate it! It's a FORTH Editor, Interpteter and Compiler for the ATARI computers.
|
Version 0.5.4 (01/28/2023):
|
An interactive language: This language allows a direct mode, as on a calculator, but in witch you can create new words to enhance its capabilities. On the right, let's imagine that you want to reduce a set of prices by 20%. Each time, you have to compute 80% of it. The first example gives the new price of an item at $59, it's now only $47. Note that values are first pushed on a stack and then the operator works on those numbers, the period "." is the instruction to display the top of the stack. If you don't want to type again and again the same calculations, you create a new word reduc using the pair : ; and it is used to compute the new price for $70, the result is $56. You can even type a little program using here the structure list..dolist..lloop that is a loop whose indexes are an unsorted list of numbers. Inside the loop, the index i is displayed (the original price) then a space and then the reduced price (cr is a carriage return to jump to next line) system is the instruction to quit to the desktop. |
![]() Usage in direct mode |
![]() This word uses one signle variable! |
A program to code a message Let's write, step by step, a GEM program with a menu to code or decode a text message. First, the heart of the program... Let's code a word that will move each uppercase letter of the alphabet several positions ahead or back. To do this, only one variable is required: p a pointer that will go through the string and test every character.
|
Let's use our new word We will use a predefined string named pad that the Forth uses for some string results.
To decode a message without the key, we can just try the 25 differents shifts, that's done with the following structure 25 ndo..nloop.
|
![]() |
![]() Version usable within a program. |
Codage avec prompt Let's enhance a bit the system. I want the program to clearly ask for the key and the text. That is realised with the word code-decode.
|
Raw search Similarly, let's program the raw search with the 25 shifts when you don't know the key into the word multi-decode.
|
![]() |
![]() |
Let's create the menu !![]()
|
One last effort This little word to react to the Infos... entry of the menu. It's a simple alert box. |
![]() |
![]() |
The main loop! It's a classical loop to manage the AES events.
|
Auto-run or not I want that, when under the interpreter, the compilation doesn't run the program to be able to test some parts individually in interactive mode. On the other hand, when creating a standelone program with the compiler, I want the program to be run! That's again a conditional compilation using flag 13: this one is true under the interpreter and false under the compiler. Note: a stadonlone program removes the mouse at start, so v_show_c was added to get the pointer back. |
![]() |
![]() A message is coded and then a raw search is run. |
Our program in action ! When the program is run, it displays its menu and window. You can select the action and test it.. |
![]() Partial view of the raw search. |
![]() Versions 68030/68000, binaries and sources. ![]() With the kind permission of Pierre-Louis Lamballais and Eric Da Cunha. ![]() |
![]() |
Other examples in FORTH Link with the HP-41 using its serial interface. Menus, serial communication How to use the Forth instruction to drive the Supercharger as a coprocessor. Include PC assembly, Supercharger instructions Save and retore data on the BOSS-DR5 via MIDI. Menu, file, MIDI communication RTC Clock manager for the Apollo Vampire V4. Include assembly, dialog creation, dialog in a window |
![]() |
![]() |
Mixing Forth and Assembler You may want to replace code by an assembly routine. This is really simple:
|
Even better: all in one source! The assembly text code and the PRG generation can be driven directly from Forth. Here is how:
During compilation, you'll see the activity of your assembler: ![]() Note: the null argument before every directive can be used in conjunction with a flag to decide wether to execute or ignore those orders. For example, if you're working on the Forth part, you don't have to save an generate the same PRG at every compilation. |
![]() |
Variables definition | |||
---|---|---|---|
variable p \ RIM module variable t \ TRM module variable fichier \ address of file in memory variable total \ total size of file 256 string filename \ path+name 1536 allot constant PALs \ palette source 1536 allot constant PALd \ palette destination variable fhd \ file handle |
Every module is pointed at by a variable. The palettes are at their maximal size to receive 256 colors in VDI format: 256 colors × 3 components × 2-bytes word (0 to 1000) = 1536. |
||
Loading modules | |||
: main " d:\parx.sys\" 1 modset 0 t ! " parx252.trm" graphic_card negate t modload drop 0 p ! " rim\gif00.rim" -1 p modload drop |
|
||
GIF loading and decoding | |||
" F:\FORTH\GIPHY.GIF" filename $! filename 0 fopensize dup fhd ! 0> if total ! fhd @ total @ dup allot dup fichier ! fread drop fichier @ total @ filename fhd @ PALs 1 p dorim drop |
|
||
Dithering for current screen mode | |||
mfdbs mfdbd fillmfdb work_out 2- w@ mfdbd 12 + w! %b1100110 1 PALs PALd 3 t dotrm drop |
|
||
Blitting to screen | |||
mfdbd mfdbs fillmfdb PALs savevdipal PALd setvdipal 0 mfdbd ! 0 0 0 0 mfdbs 4 + w@ mfdbs 6 + w@ 3 vro_cpyfm key drop fhd @ fclose drop PALs setvdipal then p modunload t modunload ; |
|
||
If the program is compiled | |||
>comp -13 >ifflag fastopen drop main >endf |
|
Variables definitions | |||
---|---|---|---|
variable t \ TRM module variable fichier \ address of file in memory variable total \ total size of file 256 string filename 256 string chemin 32 string nom 1536 allot constant PALs 1536 allot constant PALd 20 allot constant MFDB variable fhd 100 array MODS \ the array of pointers to the modules variable nMODS \ the actual number of modules |
|
||
Selecting the image | |||
: main cls " \*.*" chemin $! " " nom $! chemin nom fsel_input chemin nom path filename $! cls |
|
||
Loading the modules | |||
" d:\parx.sys\" 1 modset ." Charment des modules..." cr 0 t ! ( " parx252.trm" graphic_card negate t ) modload drop 0 0 MODS ! ( " rim\*.rim" -1 0 MODS ) modmload .. nMODS ! ." modules chargés" cr |
|
||
Loading the image | |||
." Chargement du fichier..." cr filename 0 fopensize dup fhd ! 0> if total ! ( fhd @ total @ dup allot dup fichier ! ) fread drop |
Same as before, the whole file is loaded into memory. | ||
Finding the image type | |||
nMODS @ 0 do -1 mfdbs fillmfdb ( fichier @ total @ filename fhd @ PALs 1 i MODS ) dorim 0< ifloop |
|
||
Displaying the type | |||
dup nMODS @ = if drop ." Image non reconnue" cr else MODS modlname type cr key drop |
|
||
Displaying the image | |||
mfdbs mfdbd fillmfdb work_out 2- w@ mfdbd 12 + w! ( %b1100110 1 PALs PALd 3 t ) dotrm drop mfdbd mfdbs fillmfdb PALs savevdipal PALd setvdipal ( 0 mfdbd ! 0 0 0 0 mfdbs 4 + w@ mfdbs 6 + w@ 3 ) vro_cpyfm key drop PALs setvdipal then fhd @ fclose drop then 0 MODS nMODS @ modmunload t modunload ; >comp -13 >ifflag fastopen drop main >endf |
|
Variables definition | |||
---|---|---|---|
variable p \ WIM module variable t \ TRM module 1536 allot constant PALs \ palette source if needed 1536 allot constant PALd \ palette destination (unused in 16 bits) |
The same as before, each module requires its own variable.
Every palette has the maximum size for 256 colors. |
||
Loading modules | |||
: main absolute " d:\parx.sys\" 1 modset ." Loading modules..." cr 0 t ! " parx252.trm" graphic_card negate t modload if exit else ." TRM Ok" cr then 0 p ! " wim\tga_tc16.wim" 1 p modload if exit else ." WIM Ok" cr then remember |
|
||
Copying a screen block | |||
." Block 320x200 with palette" cr 0 mfdbs ! 0 320 200 work_out 2- w@ 0 mfdbd fillmfdb mfdbd imagesize allot mfdbd ! 0 0 0 0 320 200 3 vro_cpyfm PALs savevdipal mfdbd mfdbs fillmfdb |
|
||
In case of a graphic card | |||
( graphic_card work_out 2- w@ 4 8 <seg> ) and if ." Converting to VDI mode..." cr 1 mfdbd 10 + w! mfdbd imagesize allot mfdbd ! vr_trnfm mfdbd mfdbs fillmfdb then |
If the computer has a graphic card and the currunt mode has 4 or 8 planes, then we must turn the bloc
to the VDI independant format, else the TRM won't work.
With the TC modes (15, 16, 24 and 32 bits) it perfectly handles the blocks.
|
||
Turning the block to 16 bits | |||
." Converting to 16 bits..." cr 16 mfdbd 12 + w! %b0100011 1 PALs PALd 3 t dotrm if exit else ." Dotrm Ok" cr then mfdbd mfdbs fillmfdb |
|
||
Saving to TGA 16 bits | |||
." Saving TGA 16 bits..." cr " I:\AAA.TGA" PALd 1 p dowim if exit else ." Dowim Ok" cr then |
|
||
Cleaning memory | |||
restore t modunload p modunload relative ; |
|
![]() |
Variables definition: n will contain the limit of the sum, and the three stacks for the threads. 10 integers each, this is more than enough. |
![]() |
Computing a sum: This same word will be used by the three threads. do opens the loop from thid (the identifier 1,2 or 3) to n+1 3 +loop sets a step of 3 after each addition, the thread hands over to another with thnext |
![]() |
Code for threads #1 and #2: Here is the code executed by the first two threads, the slaves. While the value n is not zero, they compute their sum and wait for synchronization on channel zero with 0 thsync to send their result before starting again. |
![]() |
Code for thread #3: Here is the code executed by the last thread, the master.
|
![]() |
The main program: Each thread is defined, they all share page0 as only one actually writes to the screen. They have a personal stack, an ID that looks pretty to simplify our program and the name of the word that they will execute. The last defined thread is the first to gain control when thrun is executed. That ensures that our master program will be the first to pilot and synchronize the two slaves. |
![]() |
Executing the program: Main runs the three threads. The user asks for the sum from 1 to 100 that evaluates to 5050, then the sum from 1 to 2022 evaluated to 2.045.253. To stop, a zero tells the program to end, the three threads exit and are removed from the list. |
![]() |
We'll divide the FORTH window into 3 columns. The first one reserved for the direct mode, the remaining two for the threads.
One of them will display lines in color with REPLACE mode and the other black lines with a XOR writting mode.
Look at the direct mode, the program was run with main, then multitasking was stopped with Ctrl+Alt+Shift and the tasks list was displayed with thstat. You can resume execution where it stopped with thrun. |
![]() |
Variables definition: Here is how FORTH does cope with the problem of local variables, for example: 3 4 thvariable X1 creates an internal array of three values of 4 bytes each that is automatically indexed with the current thread identifier. In direct mode, ID=0, so X1(0) is accessed, using thread 1, it's X1(1) that is used, and so on. You have a total liberty to give an identifer to your threads, but when using local variables, consecutive values starting from 1 are far better. |
![]() |
Stacks and pages:
|
![]() |
Words common for both threads
Init a drawing: To start, we need two points X1,Y1 and X2,Y2 as well as a displacement dX1,dY1 and dX2,dY2 to go to the next line. Coordinates are picked at random from 0 to Xmax/Ymax (size of the thread's page) and the movement from 1 to 8 pixels. Bouncing: If a point exits the page rectangle, the word bounce changes the sign of the displacement and recomputes the position. |
![]() |
One step ahead: This word moves both pixels X1,Y1 and X2,Y2 and verifies that the pixels are inside the page. Note that in FORTH, by default coordinates are relatives to the current page. This way, no offset has to be managed by the user, the upper left corner of every page is always 0,0 from the programmer's point of view. Note that the with the case stucture you can check for other things than equality. 0 <of checks if the value is negative and Xmax @ >of checks if the value is greater than Xmax. Calling v_pline draws the line. |
![]() |
Code for thread #2: This is the one that draws black lines.
|
![]() |
Code for thread #1: This one draws lines in color.
|
![]() |
The main program: Every thread is defined not with thread but with vthread. This alternative opens a new VDI workstation for the thread allowing it to set its own graphics needs. thrun initiates the multitasking mode and the drawings start in the two rightmost columns. |
Dialog with M_PLAYER/MP_STE (and ANIPLAY)
Creating animations vd_create enters a parallel mode with the player. It's M_PLAYER that builds the animation and, for each frame, it runs a FORTH word that generates the pixels. This feature is not available with ANIPLAY. Here is a very simple example. The animation will be in 120×96 and 16 bits. At start, this is a black image (filled with nul pixels) and each time a new frame is required, the FORTH word fills 4 lines with white pixels from top to bottom (480 pixels equal to FFFF). At the end of 24 images, 4×24=96 lines will be filled, the last image is totally white.
A set of graphic functions is available in FORTH. Here are some graphic results. The main words are:
![]()
Calculation words are available:
|