Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Forth, za one sa razlčitim rasporedom vijuga...
Reply
Evo i mene da se javim. Nisam stao sa Forth-om. Radim i dalje na njemu. Svakodnevne obveze i pokretanje vlastitog posla je sve nekako postavilo na čekanje, ali i dalje radim na njemu.

Samo ću napisati što sam proučavanjem doznao.

Forth i nije tako mrtav kao što se misli. Trenutno jako malo ljudi radi na njemu, ali zajednica je i dalje živa. 
Trenutno najbolji Forth “OS-ovi” za mikrokontrolere su po meni FlashForth i Mecrisp. Oba se razvijaju i dalje, od kojih je Mecrisp zajednica življa nego FlashForth.

Mecrisp \ ********************************************************************
Pisan za više mikrokontrolera, čitav popis je kad se skine Mecrisp-stellaris datoteka u kojoj se nalazi i source kod koji je namijenjen STM32 mikrokontrolerima.
Čisti Mecrisp je pisan za Texas Instruments MSP430 mikrokontrolere

Za početnike i napredne, neslužbena dokumentacija za Mecrisp-stellaris, autor je Terry Porter:
https://mecrisp-stellaris-folkdoc.sourceforge.io/

Sadržaj je poprilično velik i pun primjera, razrađeno je puno toga, ja ću navesti samo neke od primjera.

Za totalne početnike doslovna procedura na blue pill da se dobije funkcionalan Forth na blue pill:
https://mecrisp-stellaris-folkdoc.source...lue%20pill

Na linku iznad ima sve, direktno se može skinuti hex, pripremljeni programčići za učitati itd….

Koliko čitam, većina koristi Mecrisp za TI MSP430.


Terry-jeva demonstracija rada sa step motorom :

https://www.youtube.com/watch?v=0gGkwmRNnGA


Od mog zadnjeg posta ovdje, jedan programer je napisao SWDCOM koji dozvoljava upload datoteke, odnosno programa pri brzinama većim od ekvivalentno 460800 bauda! preko terminala koristeći jeftini SWD-USB. Može se naći na prvom linku ovog posta.


Jedan od Terry-jevih programa za pomoć pri razvoju je Svd2forth-v3. Pisan je prema CMSIS-SVD standardu u kojem svi registri imaju jednaka imena bez obzira na jezgru i registre (ako sam dobro pokopčao). Ukoliko ukucaš RCC_CR dobije se ispis svakog pojedinog bita sa njegovim nazivom.
Terry-jev program automatski imenuje registre.
Primjer ispisa je:
Code:
RCC_CR2 () $00006780
                                                          H H
                                                          S S H
                                                          I I S
                                                          1 1 I
                                                          4 4 1
                               |HSICAL         |HSI14    |D R 4
                               |7:6:5:4:3:2:1:0|TRIM     |I|D|O
                               |1|1|1|1|1|1|   |4:3:2:1:0|S|Y|N
~|~|~|~|~|~|~|~|~|~|~|~|~|~|~|~|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 0 0 0 0 0 0 0


Više o tome na linku ispod:
https://mecrisp-stellaris-folkdoc.source...th-v3.html


Ti njegovi programčići su za kompletno cijeli spektar Arm jezgri, dakle potrebno je prije toga zakomentirati registre “template” koje tvoj mikrokontroler ima kako bi ti ostalo što više mjesta za program. Na linku za totalne početnike se niti to ne mora.
Nakon toga se automatski generira file koji treba ubaciti umjesto jednog defaultnog. Probao sam nije komplicirano samo zahtijeva vremena. Ja neću pisati kompletnu proceduru, koga bude zanimalo morati će pročitati manual ili pitati mene pa ću pomoći.

Ako neko bude htio probati, bitno je da se programi učitavaju točnim redosljedom! Znači prvo 1b.fs pa memmap.fs......
Terry Porter radi u unixu pa malo je možda za win korisnike teže, ali meni na linuxu sve radi na prvu.

Osim te stranice postoje dva IRC kanala na kojem se vodi rasprava svaki dan. Na Mecrisp kanalu se može komunicirati izravno s Terry-jem itd….bude svaki dan hehe. Meni je IRC na serveru pa ako mi se netko i javi ostaje mi poruka.

Toliko o Mecrisp-u. Pišem ovo za one koji bi probali, a da ne lutaju okolo po internetu

Sve ostalo o Forth-u je napisano ranije
Reply
Da nastavim….

FlashForth \ ****************************************

Da se sad malo vratimo na FlashForth, radim na njemu 11 dana povremeno, uzeo sam jedini PLC  kojim upravlja Arduino Atmega2560, a to je i ujedno jedini PLC za koji znam da ima mikrokontroler u koji je moguće upisati Forth. U tih 11 dana, u potpunosti sam savladao upravljanje ulazima, izlazima, adc konverzija, stack manipulacija, for-next petlja (nije u standardima ali FF ih je preuzeo iz gforth), definiranje novih riječi, konstante, varijable.
Čitava logika se vodi oko stack-a koji nije potrebno pamtiti jer ga ionako ispisuje na terminalu.
U početku dok sam krenuo s Forthom teško mi je bilo pohvatati kako to sve funkcionira, ali kad sam prošao određeni broj sati rada na Forthu, kao kad stisneš prekidač najednom sve postaje jasno kako to sve funkcionira. Svaka komanda se izvršava odmah nakon poziva i/ili pritiska tipke enter. Logika čitanja riječi odnosno funkcija koje su navedene u wordsAll.txt i što ona radi je zapravo vrlo jednostavna.
Za razliku od C-jezika, ovdje moraš znati što koji registar radi i što je potrebno pripremiti da se željena operacija izvrši.
Ovo je prvi put da radim s Atmega serijom mikrokontrolera. I zapravo nije mi previše bitno koji je mikrokontroler (dok netko ne ukaže na drugačije), ovaj ima ono što mi trenutno treba.


Za one koje zanima ff, ima par trikova koje je potrebno znati. U folderu se nalazi shell programčić koji radi malo drugačije nego klasični serijski programi.
Prvi put je potrebno upisati hex na mikrokontroler, u mom slučaju je to bio 2560-16MHz-38400.hex. Može se to napraviti preko jeftinog usbasp.
Nakon toga u folderu se nalazi mapa “shell” koja u sebi ima ff-shell.py pisan u pyton-u.
Arduino Mega2560 komunicira preko usb-a, ali radi kao da je spojen preko serijskog porta. Nisam puno istraživao kako…
E sad jedna možda najbitnija stvar, jako bitno je skužiti kako podesiti 200ms pauzu nakon učitavanja linije koda. Dakle, kad želite poslati nekakav program upisan u nekoj datoteci npr. File.txt, treba svaki put da program pauzira 200ms nakon svake linije, jer nekad kompajler ne uspije završiti, a kompjuter šalje naredbe. Pa onda dobijete one upitnike “?”
Za razliku od Mecrispa, Flashforth radi na brzinama od 38400 baud-a. U interaktivnom načinu rada, ja nisam primjetio nikakvu razliku u brzini. To što će tekstualnu datoteku učitavati 20 sek mi ne smeta.

Za Flashforth postoji stranica sa primjerima, a uskoro i videima koji demonstriraju programčić:

https://arduino-forth.com treba odabrati engleski jezik

Jedan korisni link s organiziranim pregledom Forth naredbi, memorijske mape....itd :

https://flashforth.com/ff5-sheet.pdf

I naravno na početnoj stranici samog ff se nalaze sve bitne razlike od standardnog Forth-a. 


U sljedećem postu ću objaviti nešto o moćnom 8-jezgrenom mikrokontroleru koji ima već upisan Forth u ROM.
Reply
Što se tiče mikrokontorelra, na tržištu postoji vrlo moćan 8-jezgreni procesor 32-bit koji se može kupiti sa upisanim FORTH-om u ROM-u. Kaže mi tražilica da ga još nije nitko spominjao ovdje na forumu pa evo malo informacija o njemu.
To je Propeller Parallax ( P2 koliko razumijem druga generacija ) koji je dizajniran za robotiku. Ima ga u FPGA implementaciji. Svaka jezgra ima svoju memoriju i jednu zajedničku. Svaka jezgra ima pristup svim 64 I/O pinovima. Svaka radi svoj posao neovisno o drugim jezgrama

I sve to u 100 pin TQFP kućištu!


Više na linkovima, jer previše ima toga da sad kopiram ovdje:

https://www.parallax.com/propeller-2/?fb...jfpSwce8aU

https://www.parallax.com/product/propell...ller-chip/


Njegova jedinstvena arhitektura:
[Image: propeller-block-large.jpg]
Slika je od prve generacije, ima duplo manje izlaza, ali poanta je u funkcioniranju.
Tko želi može direktno pročitati na linku:

http://www.hughneve.com/parallax-propeller.html

Jedna od stvari je da su svi pinovi Smart I/O pins, pa onda u čemu je stvar kod ovog mikrokontrolera koji nema serijski port? 

Kvaka je u tome što postoje za njega već postojeće datoteke za ubaciti ono što vam treba. Npr, serijski port izabereš library i eto serijski port.
To znači da nema nepotrebnih komada hardwera u samom mikrokontroleru. Naravno da se ovo neće svima svidjeti, ali meni se ta ideja jako sviđa.

Svaka od jezgri ili kako ga kreator naziva "cogs" je sposobna generirati TV/VGA video!

Kako je Forth sam po sebi jedinstven i kako ne slijedi pravila, kao niti ovaj procesor...čini mi se da su ovdje tek bezgranične mogućnosti i sposobnosti da se izvrši neki zadatak.

Jedan od Forth programa je Tachyon Forth. Neke od postavki i sadržaja:
     Default baud rate je 921600 ! i ne treba nikakva pauza u slanju podataka ! 
     Clock 20Mhz
     Nije potreban niti programator da se ubaci Forth, boota se sa SD kartice ( Fat32 )
     VGA bitmap text i grafika
     Wiznet W5500 ethernet driveri uključujući Telnet, FTP, HTTP server
     TAQOZ single op instructions <100ns
Reply
Hvala ti na jako korisnim informacijama, kako za foth tako i za ovaj parallax propeller.
Zanimljiv mi je propeller koncept čak mi se čini da ima dosta sličnosti sa RPi Pico. Problem kod ovog Propeller PII je što trenutno možeš poručiti samo uzorke a i cena mu je previsoka (15$).
Reply
Ma nema na čemu @gorankg. Ta cijena je samo za mikronkontroler. Razvojna ploča je 150$
Reply
MyFFshell (google.com)
Reply
Jedna vrlo interesantna minimalna implementacija Forth jezika u jednoj C skripti!

Code:
/*******************************************************************************
*
* A minimal Forth compiler in C
* By Leif Bruder <leifbruder@gmail.com> http://defineanswer42.wordpress.com
* Release 2014-04-04
*
* Based on Richard W.M. Jones' excellent Jonesforth sources/tutorial
*
* PUBLIC DOMAIN
*
* I, the copyright holder of this work, hereby release it into the public
* domain. This applies worldwide. In case this is not legally possible, I grant
* any entity the right to use this work for any purpose, without any conditions,
* unless such conditions are required by law.
*
*******************************************************************************/

/* Only a single include here; I'll define everything on the fly to keep
* dependencies as low as possible. In this file, the only C standard functions
* used are getchar, putchar and the EOF value. */
#include <stdio.h>

/* Base cell data types. Use short/long on most systems for 16 bit cells. */
/* Experiment here if necessary. */
#define CELL_BASE_TYPE int
#define DOUBLE_CELL_BASE_TYPE long

/* Basic memory configuration */
#define MEM_SIZE 65536 /* main memory size in bytes */
#define STACK_SIZE 192 /* cells reserved for the stack */
#define RSTACK_SIZE 64 /* cells reserved for the return stack */
#define INPUT_LINE_SIZE 32 /* bytes reserved for the WORD buffer */

/******************************************************************************/

/* Our basic data types */
typedef CELL_BASE_TYPE scell;
typedef DOUBLE_CELL_BASE_TYPE dscell;
typedef unsigned CELL_BASE_TYPE cell;
typedef unsigned DOUBLE_CELL_BASE_TYPE dcell;
typedef unsigned char byte;
#define CELL_SIZE sizeof(cell)
#define DCELL_SIZE sizeof(dcell)

/* A few constants that describe the memory layout of this implementation */
#define LATEST_POSITION INPUT_LINE_SIZE
#define HERE_POSITION (LATEST_POSITION + CELL_SIZE)
#define BASE_POSITION (HERE_POSITION + CELL_SIZE)
#define STATE_POSITION (BASE_POSITION + CELL_SIZE)
#define STACK_POSITION (STATE_POSITION + CELL_SIZE)
#define RSTACK_POSITION (STACK_POSITION + STACK_SIZE * CELL_SIZE)
#define HERE_START (RSTACK_POSITION + RSTACK_SIZE * CELL_SIZE)
#define MAX_BUILTIN_ID 71

/* Flags and masks for the dictionary */
#define FLAG_IMMEDIATE 0x80
#define FLAG_HIDDEN 0x40
#define MASK_NAMELENGTH 0x1F

/* This is the main memory to be used by this Forth. There will be no malloc
* in this file. */
byte memory[MEM_SIZE];

/* Pointers to Forth variables stored inside the main memory array */
cell *latest;
cell *here;
cell *base;
cell *state;
cell *sp;
cell *stack;
cell *rsp;
cell *rstack;

/* A few helper variables for the compiler */
int exitReq;
int errorFlag;
cell next;
cell lastIp;
cell quit_address;
cell commandAddress;
cell maxBuiltinAddress;

/* The TIB, stored outside the main memory array for now */
char lineBuffer[128];
int charsInLineBuffer = 0;
int positionInLineBuffer = 0;

/* A basic setup for defining builtins. This Forth uses impossibly low
* adresses as IDs for the builtins so we can define builtins as
* standard C functions. Slower but easier to port. */
#define BUILTIN(id, name, c_name, flags) const int c_name##_id=id; const char* c_name##_name=name; const byte c_name##_flags=flags; void c_name()
#define ADD_BUILTIN(c_name) addBuiltin(c_name##_id, c_name##_name, c_name##_flags, c_name)
typedef void(*builtin)();
builtin builtins[MAX_BUILTIN_ID] = { 0 };

/* This is our initialization script containing all the words we define in
* Forth for convenience. Focus is on simplicity, not speed. Partly copied from
* Jonesforth (see top of file). */
char *initscript_pos;
const char *initScript =
    ": DECIMAL 10 BASE ! ;\n"
    ": HEX 16 BASE ! ;\n"
    ": OCTAL 8 BASE ! ;\n"
    ": 2DUP OVER OVER ;\n"
    ": 2DROP DROP DROP ;\n"
    ": NIP SWAP DROP ;\n"
    ": 2NIP 2SWAP 2DROP ;\n"
    ": TUCK SWAP OVER ;\n"
    ": / /MOD NIP ;\n"
    ": MOD /MOD DROP ;\n"
    ": BL 32 ;\n"
    ": CR 10 EMIT ;\n"
    ": SPACE BL EMIT ;\n"
    ": NEGATE 0 SWAP - ;\n"
    ": DNEGATE 0. 2SWAP D- ;\n"
    ": CELLS CELL * ;\n"
    ": ALLOT HERE @ + HERE ! ;\n"
    ": TRUE -1 ;\n"
    ": FALSE 0 ;\n"
    ": 0= 0 = ;\n"
    ": 0< 0 < ;\n"
    ": 0> 0 > ;\n"
    ": <> = 0= ;\n"
    ": <= > 0= ;\n"
    ": >= < 0= ;\n"
    ": 0<= 0 <= ;\n"
    ": 0>= 0 >= ;\n"
    ": 1+ 1 + ;\n"
    ": 1- 1 - ;\n"
    ": 2+ 2 + ;\n"
    ": 2- 2 - ;\n"
    ": 2/ 2 / ;\n"
    ": 2* 2 * ;\n"
    ": D2/ 2. D/ ;\n"
    ": +! DUP @ ROT + SWAP ! ;\n"
    ": [COMPILE] WORD FIND >CFA , ; IMMEDIATE\n"
    ": [CHAR] key ' LIT , , ; IMMEDIATE\n"
    ": RECURSE LATEST @ >CFA , ; IMMEDIATE\n"
    ": DOCOL 0 ;\n"
    ": CONSTANT CREATE DOCOL , ' LIT , , ' EXIT , ;\n"
    ": 2CONSTANT SWAP CREATE DOCOL , ' LIT , , ' LIT , , ' EXIT , ;\n"
    ": VARIABLE HERE @ CELL ALLOT CREATE DOCOL , ' LIT , , ' EXIT , ;\n" /* TODO: Allot AFTER the code, not before */
    ": 2VARIABLE HERE @ 2 CELLS ALLOT CREATE DOCOL , ' LIT , , ' EXIT , ;\n" /* TODO: Allot AFTER the code, not before */
    ": IF ' 0BRANCH , HERE @ 0 , ; IMMEDIATE\n"
    ": THEN DUP HERE @ SWAP - SWAP ! ; IMMEDIATE\n"
    ": ELSE ' BRANCH , HERE @ 0 , SWAP DUP HERE @ SWAP - SWAP ! ; IMMEDIATE\n"
    ": BEGIN HERE @ ; IMMEDIATE\n"
    ": UNTIL ' 0BRANCH , HERE @ - , ; IMMEDIATE\n"
    ": AGAIN ' BRANCH , HERE @ - , ; IMMEDIATE\n"
    ": WHILE ' 0BRANCH , HERE @ 0 , ; IMMEDIATE\n"
    ": REPEAT ' BRANCH , SWAP HERE @ - , DUP HERE @ SWAP - SWAP ! ; IMMEDIATE\n"
    ": UNLESS ' 0= , [COMPILE] IF ; IMMEDIATE\n"
    ": DO HERE @ ' SWAP , ' >R , ' >R , ; IMMEDIATE\n"
    ": LOOP ' R> , ' R> , ' SWAP , ' 1+ , ' 2DUP , ' = , ' 0BRANCH , HERE @ - , ' 2DROP , ; IMMEDIATE\n"
    ": +LOOP ' R> , ' R> , ' SWAP , ' ROT , ' + , ' 2DUP , ' <= , ' 0BRANCH , HERE @ - , ' 2DROP , ; IMMEDIATE\n"
    ": I ' R@ , ; IMMEDIATE\n"
    ": SPACES DUP 0> IF 0 DO SPACE LOOP ELSE DROP THEN ;\n"
    ": ABS DUP 0< IF NEGATE THEN ;\n"
    ": DABS 2DUP 0. D< IF DNEGATE THEN ;\n"
    ": .DIGIT DUP 9 > IF 55 ELSE 48 THEN + EMIT ;\n"
    ": .SIGN DUP 0< IF 45 EMIT NEGATE THEN ;\n" /* BUG: 10000000000... will be shown wrong */
    ": .POS BASE @ /MOD ?DUP IF RECURSE THEN .DIGIT ;\n"
    ": . .SIGN DUP IF .POS ELSE .DIGIT THEN ;\n"
    ": COUNTPOS SWAP 1 + SWAP BASE @ / ?DUP IF RECURSE THEN ;\n"
    ": DIGITS DUP 0< IF 1 ELSE 0 THEN SWAP COUNTPOS ;\n"
    ": .R OVER DIGITS - SPACES . ;\n"
    ": . . SPACE ;\n"
    ": ? @ . ;\n"
    ": .S DSP@ BEGIN DUP S0@ > WHILE DUP ? CELL - REPEAT DROP ;\n"
    ": TYPE 0 DO DUP C@ EMIT 1 + LOOP DROP ;\n"
    ": ALIGN BEGIN HERE @ CELL MOD WHILE 0 C, REPEAT ;\n"
    ": s\" ' LITSTRING , HERE @ 0 , BEGIN KEY DUP 34 <> WHILE C, REPEAT DROP DUP HERE @ SWAP - CELL - SWAP ! ALIGN ; IMMEDIATE\n"
    ": .\" [COMPILE] s\" ' TYPE , ; IMMEDIATE\n"
    ": ( BEGIN KEY [CHAR] ) = UNTIL ; IMMEDIATE\n"
    ": COUNT DUP 1+ SWAP C@ ;\n"
    ": MIN 2DUP < IF DROP ELSE NIP THEN ;\n"
    ": MAX 2DUP > IF DROP ELSE NIP THEN ;\n"
    ": D0= OR 0= ;\n"
    ": DMIN 2OVER 2OVER D< IF 2DROP ELSE 2NIP THEN ;\n"
    ": DMAX 2OVER 2OVER D> IF 2DROP ELSE 2NIP THEN ;\n"
    ;

/******************************************************************************/

/* The primary data output function. This is the place to change if you want
* to e.g. output data on a microcontroller via a serial interface. */
void putkey(char c)
{
    putchar(c);
}

/* The primary data input function. This is where you place the code to e.g.
* read from a serial line. */
int llkey()
{
    if (*initscript_pos) return *(initscript_pos++);
    return getchar();
}

/* Anything waiting in the keyboard buffer? */
int keyWaiting()
{
    return positionInLineBuffer < charsInLineBuffer ? -1 : 0;
}

/* Line buffered character input. We're duplicating the functionality of the
* stdio library here to make the code easier to port to other input sources */
int getkey()
{
    int c;

    if (keyWaiting())
        return lineBuffer[positionInLineBuffer++];

    charsInLineBuffer = 0;
    while ((c = llkey()) != EOF)
    {
        if (charsInLineBuffer == sizeof(lineBuffer)) break;
        lineBuffer[charsInLineBuffer++] = c;
        if (c == '\n') break;
    }

    positionInLineBuffer = 1;
    return lineBuffer[0];
}

/* C string output */
void tell(const char *str)
{
    while (*str)
        putkey(*str++);
}

/* The basic (data) stack operations */

cell pop()
{
    if (*sp == 1)
    {
        tell("? Stack underflow\n");
        errorFlag = 1;
        return 0;
    }
    return stack[--(*sp)];
}

cell tos()
{
    if (*sp == 1)
    {
        tell("? Stack underflow\n");
        errorFlag = 1;
        return 0;
    }
    return stack[(*sp)-1];
}

void push(cell data)
{
    if (*sp >= STACK_SIZE)
    {
        tell("? Stack overflow\n");
        errorFlag = 1;
        return;
    }
    stack[(*sp)++] = data;
}

dcell dpop()
{
    cell tmp[2];
    tmp[1] = pop();
    tmp[0] = pop();
    return *((dcell*)tmp);
}

void dpush(dcell data)
{
    cell tmp[2];
    *((dcell*)tmp) = data;
    push(tmp[0]);
    push(tmp[1]);
}

/* The basic return stack operations */

cell rpop()
{
    if (*rsp == 1)
    {
        tell("? RStack underflow\n");
        errorFlag = 1;
        return 0;
    }
    return rstack[--(*rsp)];
}

void rpush(cell data)
{
    if (*rsp >= RSTACK_SIZE)
    {
        tell("? RStack overflow\n");
        errorFlag = 1;
        return;
    }
    rstack[(*rsp)++] = data;
}

/* Secure memory access */

cell readMem(cell address)
{
    if (address > MEM_SIZE)
    {
        tell("Internal error in readMem: Invalid addres\n");
        errorFlag = 1;
        return 0;
    }
    return *((cell*)(memory + address));
}

void writeMem(cell address, cell value)
{
    if (address > MEM_SIZE)
    {
        tell("Internal error in writeMem: Invalid address\n");
        errorFlag = 1;
        return;
    }
    *((cell*)(memory + address)) = value;
}

/* Reading a word into the input line buffer */
byte readWord()
{
    char *line = (char*)memory;
    byte len = 0;
    int c;

    while ((c = getkey()) != EOF)
    {
        if (c == ' ') continue;
        if (c == '\n') continue;
        if (c != '\\') break;

        while ((c = getkey()) != EOF)
            if (c == '\n')
                break;
    }

    while (c != ' ' && c != '\n' && c != EOF)
    {
        if (len >= (INPUT_LINE_SIZE - 1))
            break;
        line[++len] = c;
        c = getkey();
    }
    line[0] = len;
    return len;
}

/* toupper() clone so we don't have to pull in ctype.h */
char up(char c)
{
    return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c;
}

/* Dictionary lookup */
cell findWord(cell address, cell len)
{
    cell ret = *latest;
    char *name = (char*)&memory[address];
    cell i;
    int found;

    for (ret = *latest; ret; ret = readMem(ret))
    {
        if ((memory[ret + CELL_SIZE] & MASK_NAMELENGTH) != len) continue;
        if (memory[ret + CELL_SIZE] & FLAG_HIDDEN) continue;

        found = 1;
        for (i = 0; i < len; i++)
        {
            if (up(memory[ret + i + 1 + CELL_SIZE]) != up(name[i]))
            {
                found = 0;
                break;
            }
        }
        if (found) break;
    }
    return ret;
}

/* Basic number parsing, base <= 36 only atm */
void parseNumber(byte *word, cell len, dcell *number, cell *notRead, byte *isDouble)
{
    int negative = 0;
    cell i;
    char c;
    cell current;

    *number = 0;
    *isDouble = 0;

    if (len == 0)
    {
        *notRead = 0;
        return;
    }

    if (word[0] == '-')
    {
        negative = 1;
        len--;
        word++;
    }
    else if (word[0] == '+')
    {
        len--;
        word++;
    }

    for (i = 0; i < len; i++)
    {
        c = *word;
        word++;
        if (c == '.') { *isDouble = 1; continue; }
        else if (c >= '0' && c <= '9') current = c - '0';
        else if (c >= 'A' && c <= 'Z') current = 10 + c - 'A';
        else if (c >= 'a' && c <= 'z') current = 10 + c - 'a';
        else break;

        if (current >= *base) break;

        *number = *number * *base + current;
    }

    *notRead = len - i;
    if (negative) *number = (-((scell)*number));
}

/*******************************************************************************
*
* Builtin definitions
*
*******************************************************************************/

BUILTIN(0, "RUNDOCOL", docol, 0)
{
    rpush(lastIp);
    next = commandAddress + CELL_SIZE;
}

/* The first few builtins are very simple, not need to waste vertical space here */
BUILTIN( 1, "CELL",      doCellSize,      0)              { push(CELL_SIZE); }
BUILTIN( 2, "@",         memRead,         0)              { push(readMem(pop())); }
BUILTIN( 3, "C@",        memReadByte,     0)              { push(memory[pop()]); }
BUILTIN( 4, "KEY",       key,             0)              { push(getkey()); }
BUILTIN( 5, "EMIT",      emit,            0)              { putkey(pop() & 255); }
BUILTIN( 6, "DROP",      drop,            0)              { pop(); }
BUILTIN( 7, "EXIT",      doExit,          0)              { next = rpop(); }
BUILTIN( 8, "BYE",       bye,             0)              { exitReq = 1; }
BUILTIN( 9, "LATEST",    doLatest,        0)              { push(LATEST_POSITION); }
BUILTIN(10, "HERE",      doHere,          0)              { push(HERE_POSITION); }
BUILTIN(11, "BASE",      doBase,          0)              { push(BASE_POSITION); }
BUILTIN(12, "STATE",     doState,         0)              { push(STATE_POSITION); }
BUILTIN(13, "[",         gotoInterpreter, FLAG_IMMEDIATE) { *state = 0; }
BUILTIN(14, "]",         gotoCompiler,    0)              { *state = 1; }
BUILTIN(15, "HIDE",      hide,            0)              { memory[*latest + CELL_SIZE] ^= FLAG_HIDDEN; }
BUILTIN(16, "R>",        rtos,            0)              { push(rpop()); }
BUILTIN(17, ">R",        stor,            0)              { rpush(pop()); }
BUILTIN(18, "KEY?",      key_p,           0)              { push(keyWaiting()); }
BUILTIN(19, "BRANCH",    branch,          0)              { next += readMem(next); }
BUILTIN(20, "0BRANCH",   zbranch,         0)              { next += pop() ? CELL_SIZE : readMem(next); }
BUILTIN(21, "IMMEDIATE", toggleImmediate, FLAG_IMMEDIATE) { memory[*latest + CELL_SIZE] ^= FLAG_IMMEDIATE; }
BUILTIN(22, "FREE",      doFree,          0)              { push(MEM_SIZE - *here); }
BUILTIN(23, "S0@",       s0_r,            0)              { push(STACK_POSITION + CELL_SIZE); }
BUILTIN(24, "DSP@",      dsp_r,           0)              { push(STACK_POSITION + *sp * CELL_SIZE); }
BUILTIN(25, "NOT",       not,             0)              { push(~pop()); }
BUILTIN(26, "DUP",       dup,             0)              { push(tos()); }

BUILTIN(27, "!", memWrite, 0)
{
    cell address = pop();
    cell value = pop();
    writeMem(address, value);
}

BUILTIN(28, "C!", memWriteByte, 0)
{
    cell address = pop();
    cell value = pop();
    memory[address] = value & 255;
}

BUILTIN(29, "SWAP", swap, 0)
{
    cell a = pop();
    cell b = pop();
    push(a);
    push(b);
}

BUILTIN(30, "OVER", over, 0)
{
    cell a = pop();
    cell b = tos();
    push(a);
    push(b);
}

BUILTIN(31, ",", comma, 0)
{
    push(*here);
    memWrite();
    *here += CELL_SIZE;
}

BUILTIN(32, "C,", commaByte, 0)
{
    push(*here);
    memWriteByte();
    *here += sizeof(byte);
}

BUILTIN(33, "WORD", word, 0)
{
    byte len = readWord();
    push(1);
    push(len);
}

BUILTIN(34, "FIND", find, 0)
{
    cell len = pop();
    cell address = pop();
    cell ret = findWord(address, len);
    push(ret);
}

cell getCfa(cell address)
{
    byte len = (memory[address + CELL_SIZE] & MASK_NAMELENGTH) + 1;
    while ((len & (CELL_SIZE-1)) != 0) len++;
    return address + CELL_SIZE + len;
}

BUILTIN(35, ">CFA", cfa, 0)
{
    cell address = pop();
    cell ret = getCfa(address);
    if (ret < maxBuiltinAddress)
        push(readMem(ret));
    else
        push(ret);
}

BUILTIN(36, "NUMBER", number, 0)
{
    dcell num;
    cell notRead;
    byte isDouble;
    cell len = pop();
    byte* address = &memory[pop()];
    parseNumber(address, len, &num, &notRead, &isDouble);
    if (isDouble) dpush(num); else push((cell)num);
    push(notRead);
}

BUILTIN(37, "LIT", lit, 0)
{
    push(readMem(next));
    next += CELL_SIZE;
}

/* Outer and inner interpreter, TODO split up */
BUILTIN(38, "QUIT", quit, 0)
{
    cell address;
    dcell number;
    cell notRead;
    cell command;
    int i;
    byte isDouble;
    cell tmp[2];

    int immediate;

    for (exitReq = 0; exitReq == 0;)
    {
        lastIp = next = quit_address;
        errorFlag = 0;

        word();
        find();

        address = pop();
        if (address)
        {
            immediate = (memory[address + CELL_SIZE] & FLAG_IMMEDIATE);
            commandAddress = getCfa(address);
            command = readMem(commandAddress);
            if (*state && !immediate)
            {
                if (command < MAX_BUILTIN_ID && command != docol_id)
                    push(command);
                else
                    push(commandAddress);
                comma();
            }
            else
            {
                while (!errorFlag && !exitReq)
                {
                    if (command == quit_id) break;
                    else if (command < MAX_BUILTIN_ID) builtins[command]();
                    else
                    {
                        lastIp = next;
                        next = command;
                    }

                    commandAddress = next;
                    command = readMem(commandAddress);
                    next += CELL_SIZE;
                }
            }
        }
        else
        {
            parseNumber(&memory[1], memory[0], &number, &notRead, &isDouble);
            if (notRead)
            {
                tell("Unknown word: ");
                for (i=0; i<memory[0]; i++)
                    putkey(memory[i+1]);
                putkey('\n');

                *sp = *rsp = 1;
                continue;
            }
            else
            {
                if (*state)
                {
                    *((dcell*)tmp) = number;
                    push(lit_id);
                    comma();

                    if (isDouble)
                    {
                        push(tmp[0]);
                        comma();
                        push(lit_id);
                        comma();
                        push(tmp[1]);
                        comma();
                    }
                    else
                    {
                        push((cell)number);
                        comma();
                    }
                }
                else
                {
                    if (isDouble) dpush(number); else push((cell)number);
                }
            }
        }

        if (errorFlag)
            *sp = *rsp = 1;
        else if (!keyWaiting() && !(*initscript_pos))
            tell(" OK\n");
    }
}

BUILTIN(39, "+", plus, 0)
{
    scell n1 = pop();
    scell n2 = pop();
    push(n1 + n2);
}

BUILTIN(40, "-", minus, 0)
{
    scell n1 = pop();
    scell n2 = pop();
    push(n2 - n1);
}

BUILTIN(41, "*", mul, 0)
{
    scell n1 = pop();
    scell n2 = pop();
    push(n1 * n2);
}

BUILTIN(42, "/MOD", divmod, 0)
{
    scell n1 = pop();
    scell n2 = pop();
    push(n2 % n1);
    push(n2 / n1);
}

BUILTIN(43, "ROT", rot, 0)
{
    cell a = pop();
    cell b = pop();
    cell c = pop();
    push(b);
    push(a);
    push(c);
}

void createWord(const char* name, byte len, byte flags);
BUILTIN(44, "CREATE", doCreate, 0)
{
    byte len;
    cell address;
    word();
    len = pop() & 255;
    address = pop();
    createWord((char*)&memory[address], len, 0);
}

BUILTIN(45, ":", colon, 0)
{
    doCreate();
    push(docol_id);
    comma();
    hide();
    *state = 1;
}

BUILTIN(46, ";", semicolon, FLAG_IMMEDIATE)
{
    push(doExit_id);
    comma();
    hide();
    *state = 0;
}

BUILTIN(47, "R@", rget, 0)
{
    cell tmp = rpop();
    rpush(tmp);
    push(tmp);
}

BUILTIN(48, "J", doJ, 0)
{
    cell tmp1 = rpop();
    cell tmp2 = rpop();
    cell tmp3 = rpop();
    rpush(tmp3);
    rpush(tmp2);
    rpush(tmp1);
    push(tmp3);
}

BUILTIN(49, "'", tick, FLAG_IMMEDIATE)
{
    word();
    find();
    cfa();

    if (*state)
    {
        push(lit_id);
        comma();
        comma();
    }
}

BUILTIN(50, "=", equals, 0)
{
    cell a1 = pop();
    cell a2 = pop();
    push(a2 == a1 ? -1 : 0);
}

BUILTIN(51, "<", smaller, 0)
{
    scell a1 = pop();
    scell a2 = pop();
    push(a2 < a1 ? -1 : 0);
}

BUILTIN(52, ">", larger, 0)
{
    scell a1 = pop();
    scell a2 = pop();
    push(a2 > a1 ? -1 : 0);
}

BUILTIN(53, "AND", doAnd, 0)
{
    cell a1 = pop();
    cell a2 = pop();
    push(a2 & a1);
}

BUILTIN(54, "OR", doOr, 0)
{
    cell a1 = pop();
    cell a2 = pop();
    push(a2 | a1);
}

BUILTIN(55, "?DUP", p_dup, 0)
{
    cell a = tos();
    if (a) push(a);
}

BUILTIN(56, "LITSTRING", litstring, 0)
{
    cell length = readMem(next);
    next += CELL_SIZE;
    push(next);
    push(length);
    next += length;
    while (next & (CELL_SIZE-1))
        next++;
}

BUILTIN(57, "XOR", xor, 0)
{
    cell a = pop();
    cell b = pop();
    push(a ^ b);
}

BUILTIN(58, "*/", timesDivide, 0)
{
    cell n3 = pop();
    dcell n2 = pop();
    dcell n1 = pop();
    dcell r = (n1 * n2) / n3;
    push((cell)r);
    if ((cell)r != r)
    {
        tell("Arithmetic overflow\n");
        errorFlag = 1;
    }
}

BUILTIN(59, "*/MOD", timesDivideMod, 0)
{
    cell n3 = pop();
    dcell n2 = pop();
    dcell n1 = pop();
    dcell r = (n1 * n2) / n3;
    dcell m = (n1 * n2) % n3;
    push((cell)m);
    push((cell)r);
    if ((cell)r != r)
    {
        tell("Arithmetic overflow\n");
        errorFlag = 1;
    }
}

BUILTIN(60, "D=", dequals, 0)
{
    dcell a1 = dpop();
    dcell a2 = dpop();
    push(a2 == a1 ? -1 : 0);
}

BUILTIN(61, "D<", dsmaller, 0)
{
    dscell a1 = dpop();
    dscell a2 = dpop();
    push(a2 < a1 ? -1 : 0);
}

BUILTIN(62, "D>", dlarger, 0)
{
    dscell a1 = dpop();
    dscell a2 = dpop();
    push(a2 > a1 ? -1 : 0);
}

BUILTIN(63, "DU<", dusmaller, 0)
{
    dcell a1 = dpop();
    dcell a2 = dpop();
    push(a2 < a1 ? -1 : 0);
}

BUILTIN(64, "D+", dplus, 0)
{
    dscell n1 = dpop();
    dscell n2 = dpop();
    dpush(n1 + n2);
}

BUILTIN(65, "D-", dminus, 0)
{
    dscell n1 = dpop();
    dscell n2 = dpop();
    dpush(n2 - n1);
}

BUILTIN(66, "D*", dmul, 0)
{
    dscell n1 = dpop();
    dscell n2 = dpop();
    dpush(n1 * n2);
}

BUILTIN(67, "D/", ddiv, 0)
{
    dscell n1 = dpop();
    dscell n2 = dpop();
    dpush(n2 / n1);
}

BUILTIN(68, "2SWAP", dswap, 0)
{
    dcell a = dpop();
    dcell b = dpop();
    dpush(a);
    dpush(b);
}

BUILTIN(69, "2OVER", dover, 0)
{
    dcell a = dpop();
    dcell b = dpop();
    dpush(b);
    dpush(a);
    dpush(b);
}

BUILTIN(70, "2ROT", drot, 0)
{
    dcell a = dpop();
    dcell b = dpop();
    dcell c = dpop();
    dpush(b);
    dpush(a);
    dpush(c);
}

/*******************************************************************************
*
* Loose ends
*
*******************************************************************************/

/* Create a word in the dictionary */
void createWord(const char* name, byte len, byte flags)
{
    cell newLatest = *here;
    push(*latest);
    comma();
    push(len | flags);
    commaByte();
    while (len--)
    {
        push(*name);
        commaByte();
        name++;
    }
    while (*here & (CELL_SIZE-1))
    {
        push(0);
        commaByte();
    }
    *latest = newLatest;
}

/* A simple strlen clone so we don't have to pull in string.h */
byte slen(const char *str)
{
    byte ret = 0;
    while (*str++) ret++;
    return ret;
}

/* Add a builtin to the dictionary */
void addBuiltin(cell code, const char* name, const byte flags, builtin f)
{
    if (errorFlag) return;

    if (code >= MAX_BUILTIN_ID)
    {
        tell("Error adding builtin ");
        tell(name);
        tell(": Out of builtin IDs\n");
        errorFlag = 1;
        return;
    }

    if (builtins[code] != 0)
    {
        tell("Error adding builtin ");
        tell(name);
        tell(": ID given twice\n");
        errorFlag = 1;
        return;
    }

    builtins[code] = f;
    createWord(name, slen(name), flags);
    push(code);
    comma();
    push(doExit_id);
    comma();
}

/* Program setup and jump to outer interpreter */
int main()
{
    errorFlag = 0;

    if (DCELL_SIZE != 2*CELL_SIZE)
    {
        tell("Configuration error: DCELL_SIZE != 2*CELL_SIZE\n");
        return 1;
    }

    state = (cell*)&memory[STATE_POSITION];
    base = (cell*)&memory[BASE_POSITION];
    latest = (cell*)&memory[LATEST_POSITION];
    here = (cell*)&memory[HERE_POSITION];
    sp = (cell*)&memory[STACK_POSITION];
    stack = (cell*)&memory[STACK_POSITION + CELL_SIZE];
    rsp = (cell*)&memory[RSTACK_POSITION];
    rstack = (cell*)&memory[RSTACK_POSITION + CELL_SIZE];

    *sp = *rsp = 1;
    *state = 0;
    *base = 10;
    *latest = 0;
    *here = HERE_START;

    ADD_BUILTIN(docol);
    ADD_BUILTIN(doCellSize);
    ADD_BUILTIN(memRead);
    ADD_BUILTIN(memWrite);
    ADD_BUILTIN(memReadByte);
    ADD_BUILTIN(memWriteByte);
    ADD_BUILTIN(key);
    ADD_BUILTIN(emit);
    ADD_BUILTIN(swap);
    ADD_BUILTIN(dup);
    ADD_BUILTIN(drop);
    ADD_BUILTIN(over);
    ADD_BUILTIN(comma);
    ADD_BUILTIN(commaByte);
    ADD_BUILTIN(word);
    ADD_BUILTIN(find);
    ADD_BUILTIN(cfa);
    ADD_BUILTIN(doExit);
    ADD_BUILTIN(quit);
    quit_address = getCfa(*latest);
    ADD_BUILTIN(number);
    ADD_BUILTIN(bye);
    ADD_BUILTIN(doLatest);
    ADD_BUILTIN(doHere);
    ADD_BUILTIN(doBase);
    ADD_BUILTIN(doState);
    ADD_BUILTIN(plus);
    ADD_BUILTIN(minus);
    ADD_BUILTIN(mul);
    ADD_BUILTIN(divmod);
    ADD_BUILTIN(rot);
    ADD_BUILTIN(gotoInterpreter);
    ADD_BUILTIN(gotoCompiler);
    ADD_BUILTIN(doCreate);
    ADD_BUILTIN(hide);
    ADD_BUILTIN(lit);
    ADD_BUILTIN(colon);
    ADD_BUILTIN(semicolon);
    ADD_BUILTIN(rtos);
    ADD_BUILTIN(stor);
    ADD_BUILTIN(rget);
    ADD_BUILTIN(doJ);
    ADD_BUILTIN(tick);
    ADD_BUILTIN(key_p);
    ADD_BUILTIN(equals);
    ADD_BUILTIN(smaller);
    ADD_BUILTIN(larger);
    ADD_BUILTIN(doAnd);
    ADD_BUILTIN(doOr);
    ADD_BUILTIN(branch);
    ADD_BUILTIN(zbranch);
    ADD_BUILTIN(toggleImmediate);
    ADD_BUILTIN(doFree);
    ADD_BUILTIN(p_dup);
    ADD_BUILTIN(s0_r);
    ADD_BUILTIN(dsp_r);
    ADD_BUILTIN(litstring);
    ADD_BUILTIN(not);
    ADD_BUILTIN(xor);
    ADD_BUILTIN(timesDivide);
    ADD_BUILTIN(timesDivideMod);
    ADD_BUILTIN(dequals);
    ADD_BUILTIN(dsmaller);
    ADD_BUILTIN(dlarger);
    ADD_BUILTIN(dusmaller);
    ADD_BUILTIN(dplus);
    ADD_BUILTIN(dminus);
    ADD_BUILTIN(dmul);
    ADD_BUILTIN(ddiv);
    ADD_BUILTIN(dswap);
    ADD_BUILTIN(dover);
    ADD_BUILTIN(drot);

    maxBuiltinAddress = (*here) - 1;

    if (errorFlag) return 1;

    initscript_pos = (char*)initScript;
    quit();
    return 0;
}
Reply
Evo i jedna knjiga za Forth pocetnike:
https://www.forth.com/wp-content/uploads...-FORTH.pdf
Reply
Bez uvrede ka Forth ljubiteljima, (Miki cak i zna da sam odrastao na Forth-u, zahvaljujuci njegovom ocu), ali u danasnje vreme apsolutno ne vidim potrebu za tako necim, pa me licno interesuje otkud tolika pomama za Forth-om kad je arhitektuka procesora drugacija, pa cak i C optimizovana?
Ovo nije kritika, vec samo pitanje, jer se svodi na razliku C64 i PC(Mac,…)
Reply
U mom slucaju imam potrebe za dinamickom biznis logikom pa istrzujem u vezi te teme.
Treba mi interpreter, iskoristio bih ga kao mikro-virtualnu-masinu koja u letu moze da se reprogramira.
Vrlo sam skucen sa resursima (single core CortexA) i otuda prvo razmatram Forth kao najbrzi interpreter, necu valjda sa JavaScript da radim ; )
Ideja mi je da Forth samo radi jedan mali-kritican deo logike koji je sklon promenama i da se samo time bavi, sve ostalo je suv C/C++.
Reply
Malo samo da pojasnim zasto razmisljm u pravcu Forth-a i interpretera generalno.
Ima zahtev da pokrijem neke razne use-case-ove, neki razliciti provajderi usluga iz iste branse, radi se o ostim tj vrlo slicnim stvarima (podacima) ali svaki provajder ima svoje neke specificne zahteve i procedure.
Imam takvih 5-6 provajdera i u najavi su mi novi provajderi za koje jos ne znam kako konkretno rade.
Doveloperi koji rade samnog izginuli da nadju "presek" svih tih zahteva, kako god da dizajniraju sistem jedan od provajdera im se ne uklapa u tu logiku.

Moja ideja je to "sto se ne uklapa" da prebacim ustvari na neki da se tako izrazim "interface/drajver", medju korak koji treba da to slozi u odnosu na to sta provajder nudi a sta meni treba za app.

Uz podatke bih slao i "instrukcije za obradu" a to bi ustvari bio mali Forth program koji bi to prepakovao kako treba.

Da nemam tako nesto dinamicno morao bih da radim preko nekih fiksnih konfiguracija, pa neki konfiguracioni fajlovi, pa dok samo to oko konfiguracije izhendlujem za sve provajdere opet dodjemu u problem da tom logikom ne mozemo jednostavno da pokrijemo zahtev, previse bi slozena bila "dal ima/nema ovo-ono" i tako hiljade nekih uslova koje unapred moram da predvidim.
Reply
I opet ne vidim gde je tu potreba za Forth-om. Ako stvarno postoji potreba, onda bi ga neko razvio za te stvari. Zar nije tako?
Reply
Opet kazem, u pitanju je potreba za brzim interpreterom, Forth je tu prvi na listi.

Vrlo je slozena logika u pitanju, javni transport i čekiranje putnika, vise desetina hiljada vec postavljenih uredjaja u radu (po vozovima, autobusima itd), imaju X razlicitih modela u opticaju sa razlicitim HW, uredjaj je povezan na jedno 10 razlicitih servisa da bi uopste mogao da radi, povezan je sa nacionalnom bankom za kliring transakcija jer su sad izmislili da osim specificnih "kartica za prevoz" od sad moze da se koristi sa platnim karticama (samo sa crypto sertifikatima i kljucevima da ne pricam kakva je ludnica i sto mora da nam bude uredjaj kompatibilan sa PCI standardom) ... i tu su ove moje kolege zaglavile, ne mogu to sa platnim karticama da integrisu tek tako ...

Uglavnom ovo je moje neko razmisljanje, da li ce da bude usvojeno i u produkciji to ce drugi da odluce ...

Racunaju se rute po GPS, cene za putovanja preko triangulacije nekih parametara, rezervni "odometri" kada nema GPS signala, liniski prevoz, kruzni prevoz, presedanje iz jednog u drugi transport a da vazi ista karta, gde si usao, gde si izasao, sta kada nema GPRS/4G signala, cuvaj po pulovima, kad je vozac upali/ugasio autobus, koji ti je paket usluga/tarifa, sta ako nemas sretstva na racunu, sta ako si usao i odmah izasao (predomislio si se) i tako dalje i blize ... Opsta ludnica od logike : ) ... skoro 10 godina vec rade na tom sistemu ...

Uredjaj je povezan i na Azure IoT hub, tu ima remote management, remote update, deploy sertifikata, service mode ... Bas je veselo i meni extra zanimljivo Smile
Reply
(10-29-2021, 06:19 PM)vojinilic Wrote: I opet ne vidim gde je tu potreba za Forth-om. Ako stvarno postoji potreba, onda bi ga neko razvio za te stvari. Zar nije tako?

Postoje XML-ovi i DTD-ovi i transformacije izmedju ali samo zamisli da mi treba jos i custom akcija preko toga da na primer od tri polja preko neke formule izracuna novo polje, moze da se stavi u tag parce JavaScripte i da se hakuje dalje samo je problem sto pricamo o odnosu zauzeza CPU od na primer 1:100.000 ako ne i vise ...

JavaScript+XML ili Java+XML ili Python+XML ili sta vec, kako da se to skocka da ima strukturu a i da ima akcije ako zatreba : )
Problem je sto nemam ni Java, ni Python ni JavaScript jer ne moze da se vrti na toj platformi, i ako moze to je uzasno sporo, to ne pije vodu ... 

Ima naravno XML biblioteka za C/C++ opet relativno slozene i spore ali na primer sta ako hocu da umetnem u tag parce "nečega" sto moze da se interpretira u letu, JavaScript opet?

Ili da stavim u XML tag parče Forth code-a! Big Grin

Stavi se Forth u poseban thread od aplikacije, custom Forth sa predefinisanim recima koji se bave tom problematikom, Forth ulaz/izlaz je povezan preko memoriskih pointera (zamena za stdin/out), tu je odmah dostupan direktno u memoriji apliakcije, nema FS-SYS call-ova, njemu se "prosledi" code koji treba da odradi nad tim podacima u letu i to najbrze sto moze i to bi bila njegova uloga u ovoj prici.
Reply
Momci, ovo niste videli u životu!!!! Big Grin

Probe radi uradio sam bas ovo gore sto sam pisao, u moju postojecu C/C++ aplikaciju sam implementirao Forth onaj gore sto sam pejstovao, bukvalno sam i ja pejstovao kod mene u skriptu, preminovao main() u mikiForth() i pokrenuo sam u posebnom thread-u.
Trenutno nemaju bas tridovi pojma jedan o drugom ali cu ih sigurno naterati da se upoznaju! Smile

[Image: attachment.php?aid=36501]


Attached Files Thumbnail(s)

Reply
U vezi ovog gore Forth, pisan je u C98 standardu i primer je kako stvarno moze da se minimalno napravi Forth od 20-ak reci koje su napisane u C-u kao baza pa posle od toga da se prave slozenije reci.

Na primer ovaj Forth nije trenutno thread-safe, treba malo samo da se reorganizuje memorija da to radi kako treba nezavisno.
Dobro je sto moze da se manipulise sa osnovonom velicinom podataka, tj u Forthu to zovu "cell", da li je 8,16,32,64 ili koliko ti vec treba.
Kod mene na primer na x86_64 mi je cell 64bita i double-cell 128bita, malo li je? Big Grin

Takodje ovaj Forth moze da se unapredi i jos vise ubrza, zamene se nekoliko osnovnih Forth reci da koriste napredne funkcije iz seta MMX, SSE, SSE-2, AVX ili sta vec ima na target platformi specificno za te namene, cak nije ni problem da se nakucka malo ASM-a da direktno izvrsavaju te napredne funkcije i da se to proglasi Forth rečima!
Reply
Ova kombinacija C++ i Forth je sve bolja i bolja, ima da ga koristin kao konzolni tool od (bilo kakve) aplikacije makar da mogu menjam u letu neke parametre kroz konzolu, da ne pisem svoju konzolu ... ovo je predobra kombinacija Smile

[Image: attachment.php?aid=36503]

[Image: attachment.php?aid=36504]


Attached Files Thumbnail(s)

Reply
Dodavanje grafike u ovaj Forth (gde ispod imam RayLib) se recimo svodi na ovo, funkcija za crtanje linije:

Code:
BUILTIN(77, "DRAW_LINE", draw_line, 0)
{
//    cell y2 = pop();
//    cell x2 = pop();
//    cell y1 = pop();
//    cell x1 = pop();
    DrawLine(pop(), pop(), pop(), pop(), CLITERAL(Color) {40, 40, 40, 255});
}

Ovde sam se posle ustvari setio da mi ne trebaju ni pomocne variable (x1,x2,y1,y2), jednostavno gurnu se 4 vrednosti koordinata na STACK i u ovoj funkciji samo se pokupi sa STACKA preko pop() funkcije, naravno mora da se zna red, jos je sve obrnuto.

Sta je sad tu zanimljivo, osim sto je implementacija C<>Forth brutalno prosta, kada se pozove ova funkcija u konzoli sa na primer:

Code:
200 200 300 300 DRAW_LINE

na ekranu se u sustini ne desi ništa!

Pokrenem na primer jos jednom istu komandu i malo pažljivije pratim ekran i na primer vidim iscrtanu liniju ali samo za trajanje jednog frejma! Smile

To se ustvari očekivalo jer imam dve potpuno asihrone stvari, glavnu GUI aplikaciju koja vrti svojim ritmom od 60FPS i Forth koji vrti nezavisno za sebe jer je u posebnom thread.

Dodao sam VIDEO FRAME SYNC funkciju, opet nesto prosto poput:

Code:
BUILTIN(76, "APP_FSYNC", app_fsync, 0)
{
    while (!frame_sync) usleep(100);
    frame_sync = 0;
}

Sa tim sam mogao da napravim neke proste eksperimente oko brzine da vidim šta sve može da se odradi izmedju dva frejm-a u Forth i došao do nekih 140.000 iteracija/komandi, dakle toliko imam "fore" izmedju dva Video frejma ili oko 8.4 miliona iteracija u sekundi na jednom x86_64 jezgru.

Code:
: TEST 700 0 DO I VUSET LOOP ;
: vv 100 0 DO test LOOP ;

APP_FSYNC vv vv
OK

Da li su ovo dobri ili loši rezultati je za diskusiju, samo napominjem da ništa nisam optimizovao, samo sam nabacao jedno na drugo i spojio.

PS: A gde je ovde VU-Metar? Smile Pa VU-Metar mi je posluzio u ekpserimentu brzine jer sam ga terao od 0-700 (to su neki pixeli = 0-100% otklon skale) i ustvari setovao sam ga izmedju frejmova prvo nekoliko puta, pa par desetina puta, kada sam stigao do 140.000 puta počeo je da "mrda" tj prekoračio sam vreme jednog frejma, tu je bilo DOSTA i stopirao sam dalje testiranje na tu temu Big Grin
Reply
Sledeći level integracije Forth-a je na GPU!!! ....  E to će da bude žešće, to tek niste videli sigurno, nisam ni ja Smile
Ima da ga provučem kroz vektor i fragmet "šejder", verteks kao osnovnu velicinu mogu da iskoristim na razne načine i da šta znam radim sa tri paralelna Forth-a istovremeno sinhrono ili sta već (PS: Propeller2 ?? : ) i tako u jedno ne znam, recimo 100.000 instanci paralelno ili "scena sa 100.000 vertexa" (to je ništa za moderne GPU) ...

Sta može da se uradi na GPU RX580 sa 8GB RAM-a u Forth-u? Big Grin (osim što može da se napravi dobar "kripto majner" : )

[Image: attachment.php?aid=36515]



Attached Files Thumbnail(s)

Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)