]> code.bitgloo.com Git - clyne/sprit-forth.git/commitdiff
add msp430 proof-of-concept
authorClyne Sullivan <clyne@bitgloo.com>
Sun, 26 Nov 2023 23:51:01 +0000 (18:51 -0500)
committerClyne Sullivan <clyne@bitgloo.com>
Sun, 26 Nov 2023 23:51:01 +0000 (18:51 -0500)
.gitignore
compat.txt [new file with mode: 0644]
msp430.cpp [new file with mode: 0644]

index 2ea588d726e4b00edebb808fa1a0b02e8117a853..6dbd7b0473f8766ca85c4ff1795854dd000cfbc7 100644 (file)
@@ -2,3 +2,4 @@
 *.a
 *.o
 sprit
+msp430
diff --git a/compat.txt b/compat.txt
new file mode 100644 (file)
index 0000000..3a06bbb
--- /dev/null
@@ -0,0 +1,133 @@
+yes 6.1.0010 !
+    6.1.0030 #
+    6.1.0040 #>
+    6.1.0050 #S
+yes 6.1.0070 '
+yes 6.1.0080 (
+yes 6.1.0090 *
+    6.1.0100 */
+    6.1.0110 */MOD
+yes 6.1.0120 +
+yes 6.1.0130 +!
+yes 6.1.0140 +LOOP
+yes 6.1.0150 ,
+yes 6.1.0160 -
+yes 6.1.0180 .
+yes 6.1.0190 ."
+yes 6.1.0230 /
+    6.1.0240 /MOD
+yes 6.1.0250 0<
+yes 6.1.0270 0=
+yes 6.1.0290 1+
+yes 6.1.0300 1-
+yes 6.1.0310 2!
+yes 6.1.0320 2*
+yes 6.1.0330 2/
+yes 6.1.0350 2@
+yes 6.1.0370 2DROP
+yes 6.1.0380 2DUP
+yes 6.1.0400 2OVER
+yes 6.1.0430 2SWAP
+yes 6.1.0450 :
+yes 6.1.0460 ;
+yes 6.1.0480 <
+    6.1.0490 <#
+yes 6.1.0530 =
+yes 6.1.0540 >
+    6.1.0550 >BODY
+    6.1.0560 >IN
+    6.1.0570 >NUMBER
+yes 6.1.0580 >R
+yes 6.1.0630 ?DUP
+yes 6.1.0650 @
+    6.1.0670 ABORT
+    6.1.0680 ABORT"
+yes 6.1.0690 ABS
+yes 6.1.0695 ACCEPT
+yes 6.1.0705 ALIGN
+yes 6.1.0706 ALIGNED
+yes 6.1.0710 ALLOT
+yes 6.1.0720 AND
+    6.1.0750 BASE
+yes 6.1.0760 BEGIN
+yes 6.1.0770 BL
+yes 6.1.0850 C!
+yes 6.1.0860 C,
+yes 6.1.0870 C@
+yes 6.1.0880 CELL+
+yes 6.1.0890 CELLS
+yes 6.1.0895 CHAR
+yes 6.1.0897 CHAR+
+yes 6.1.0898 CHARS
+yes 6.1.0950 CONSTANT
+yes 6.1.0980 COUNT
+yes 6.1.0990 CR
+yes 6.1.1000 CREATE
+    6.1.1170 DECIMAL
+    6.1.1200 DEPTH
+yes 6.1.1240 DO
+yes 6.1.1250 DOES>
+yes 6.1.1260 DROP
+yes 6.1.1290 DUP
+yes 6.1.1310 ELSE
+yes 6.1.1320 EMIT
+yes 6.1.1345 ENVIRONMENT?
+    6.1.1360 EVALUATE
+yes 6.1.1370 EXECUTE
+yes 6.1.1380 EXIT
+yes 6.1.1540 FILL
+    6.1.1550 FIND
+    6.1.1561 FM/MOD
+yes 6.1.1650 HERE
+    6.1.1670 HOLD
+yes 6.1.1680 I
+yes 6.1.1700 IF
+yes 6.1.1710 IMMEDIATE
+yes 6.1.1720 INVERT
+yes 6.1.1730 J
+yes 6.1.1750 KEY
+yes 6.1.1760 LEAVE
+yes 6.1.1780 LITERAL
+yes 6.1.1800 LOOP
+yes 6.1.1805 LSHIFT
+    6.1.1810 M*
+yes 6.1.1870 MAX
+yes 6.1.1880 MIN
+yes 6.1.1890 MOD
+yes 6.1.1900 MOVE
+yes 6.1.1910 NEGATE
+yes 6.1.1980 OR
+yes 6.1.1990 OVER
+yes 6.1.2033 POSTPONE
+    6.1.2050 QUIT
+yes 6.1.2060 R>
+yes 6.1.2070 R@
+yes 6.1.2120 RECURSE
+yes 6.1.2140 REPEAT
+yes 6.1.2160 ROT
+yes 6.1.2162 RSHIFT
+yes 6.1.2165 S"
+    6.1.2170 S>D
+    6.1.2210 SIGN
+    6.1.2214 SM/REM
+    6.1.2216 SOURCE
+yes 6.1.2220 SPACE
+yes 6.1.2230 SPACES
+yes 6.1.2250 STATE
+yes 6.1.2260 SWAP
+yes 6.1.2270 THEN
+yes 6.1.2310 TYPE
+    6.1.2320 U.
+    6.1.2340 U<
+    6.1.2360 UM*
+    6.1.2370 UM/MOD
+yes 6.1.2380 UNLOOP
+yes 6.1.2390 UNTIL
+yes 6.1.2410 VARIABLE
+yes 6.1.2430 WHILE
+yes 6.1.2450 WORD
+yes 6.1.2490 XOR
+yes 6.1.2500 [
+yes 6.1.2510 [']
+yes 6.1.2520 [CHAR]
+yes 6.1.2540 ]
diff --git a/msp430.cpp b/msp430.cpp
new file mode 100644 (file)
index 0000000..6c92f47
--- /dev/null
@@ -0,0 +1,353 @@
+// sprit-forth: A portable subroutine-threaded Forth.
+// Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
+//
+// This library is free software; you can redistribute it and/or modify it
+// under the terms of the GNU Library General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or (at your
+// option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
+// more details.
+//
+// You should have received a copy of the GNU Library General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+
+#include <algorithm>
+
+#include <msp430.h>
+
+#include "core.hpp"
+#include "parse.hpp"
+#include "state.hpp"
+#include "types.hpp"
+
+using DoubleCell = Cell;
+
+static char strbuf[80];
+
+static void serput(int c);
+static void serputs(const char *s);
+static void printint(DoubleCell n, int base);
+
+static void initMCU();
+static void initGPIO();
+static void initClock();
+static void initUART();
+static void Software_Trim();
+#define MCLK_FREQ_MHZ (16)
+
+static void doparse();
+
+// TODO:
+// sys m* _/ _% _' depth _rdepth _in _ev find _uma u< um/mod
+
+static void peek()           { *sp() = *(Cell *)(*sp()); }
+static void commaSP()        { comma(pop()); }
+static void discard()        { auto v = pop(); (void)v; }
+static void tobool()         { if (*sp()) *sp() = -1; }
+
+constexpr WordSet words (
+    Word("[",         WordWrap<[] { STATE = 0; }>).markImmediate(),
+    Word("]",         WordWrap<[] { STATE = -1; }>),
+    Word("@",         WordWrap<peek>),
+    Word("c@",        WordWrap<peek, [] { *sp() &= 0xFF; }>),
+    Word("!",         WordWrap<[] { auto a = (Cell *)pop(); *a = pop(); }>),
+    Word("c!",        WordWrap<[] { auto a = (char *)pop(); *a = pop(); }>),
+    Word("_d",        WordWrap<[] { *sp() += (Cell)DICT.data(); }>),
+    Word("_jmp",      WordWrap<[] { jump((FuncList)*++IP); }>),
+    Word("_jmp0",     WordWrap<[] {
+        ++IP;
+        if (pop() == 0)
+            jump((FuncList)*IP);
+    }>),
+    Word(",",         WordWrap<commaSP>),
+    Word("emit",      WordWrap<[] { serput(pop()); }>),
+    Word("key",       WordWrap<[] { push(key()); }>),
+    Word("key?",      WordWrap<[] { push(haskey()); }, tobool>),
+    Word("execute",   WordWrap<[] { (void)executor((FuncList *)pop()); }>),
+    Word(":",         WordWrap<colon>),
+    Word(";",         WordWrap<semic>).markImmediate(),
+    Word("exit",      fexit),
+    Word("drop",      WordWrap<discard>),
+    Word("dup",       WordWrap<[] { push(*sp()); }>),
+    Word("swap",      WordWrap<[] { std::swap(*sp(), *(sp() - 1)); }>),
+    Word("pick",      WordWrap<[] { auto t = *(sp() - *sp() - 1); *sp() = t; }>),
+    Word("cells",     WordWrap<[] { *sp() *= sizeof(Cell); }>),
+    Word("+",         WordWrap<[] { *(sp() - 1) += *sp(); }, discard>),
+    Word("-",         WordWrap<[] { *(sp() - 1) -= *sp(); }, discard>),
+    Word("*",         WordWrap<[] { *(sp() - 1) *= *sp(); }, discard>),
+    Word("/",         WordWrap<[] { *(sp() - 1) /= *sp(); }, discard>),
+    Word("mod",       WordWrap<[] { *(sp() - 1) %= *sp(); }, discard>),
+    Word("=",         WordWrap<[] { *(sp() - 1) = *(sp() - 1) == *sp(); }, discard, tobool>),
+    Word("<",         WordWrap<[] { *(sp() - 1) = *(sp() - 1) < *sp(); }, discard, tobool>),
+    Word("or",        WordWrap<[] { *(sp() - 1) |= *sp(); }, discard>),
+    Word("and",       WordWrap<[] { *(sp() - 1) &= *sp(); }, discard>),
+    Word("xor",       WordWrap<[] { *(sp() - 1) ^= *sp(); }, discard>),
+    Word("lshift",    WordWrap<[] { *(sp() - 1) <<= *sp(); }, discard>),
+    Word("rshift",    WordWrap<[] { *(sp() - 1) >>= *sp(); }, discard>),
+    Word(">r",        WordWrap<[] { rpush(pop()); }>),
+    Word("r>",        WordWrap<[] { push(rpop()); }>),
+    Word("immediate", WordWrap<[] { ((Word *)LATEST)->markImmediate(); }>),
+    Word("aligned",   WordWrap<[] { *sp() = aligned(*sp()); }>),
+    Word("align",     WordWrap<align>),
+    Word("literal",   WordWrap<[] { if (STATE) compileliteral(); }>).markImmediate(),
+    Word("\'",        WordWrap<tick>),
+    Word("_i",        WordWrap<[] { *sp() = ((Word *)*sp())->immediate(); }, tobool>),
+    Word("[']",       WordWrap<tick, compileliteral>).markImmediate(),
+    Word("compile,",  WordWrap<peek, commaSP>),
+    Word("word",      WordWrap<word>),
+    //Word("_b",        WordWrap<[] {
+    //    serput('#'); // Gives a good breakpoint spot for gdb
+    //}>),
+    Word(".",         WordWrap<[] { printint(pop(), BASE); }>)
+);
+
+int main()
+{
+    initMCU();
+    initialize(words);
+
+    serputs("alee forth\n\r");
+
+    while (1) {
+        doparse();
+        serputs("\n\r");
+    }
+}
+
+void getinput()
+{
+    auto ptr = strbuf;
+
+    while (1) {
+        if (UCA0IFG & UCRXIFG) {
+            auto c = static_cast<char>(UCA0RXBUF);
+            serput(c);
+
+            if (c == '\r') {
+                do {
+                    addkey(*--ptr);
+                } while (ptr != strbuf);
+
+                serputs("\n\r");
+                return;
+            } else if (c == '\b') {
+                if (ptr > strbuf)
+                    --ptr;
+            } else if (ptr < strbuf + sizeof(strbuf)) {
+                if (c >= 'A' && c <= 'Z')
+                    c += 32;
+                *ptr++ = c;
+            }
+        }
+    }
+}
+
+void doparse()
+{
+    auto result = parse();
+
+    if (result == Error::none) {
+        serputs(STATE ? "compiled" : "ok");
+    } else {
+        serputs("error ");
+        printint(static_cast<int>(result), BASE);
+    }
+}
+
+void serput(int c)
+{
+    while (!(UCA0IFG & UCTXIFG));
+    UCA0TXBUF = static_cast<char>(c);
+}
+
+void serputs(const char *s)
+{
+    while (*s)
+        serput(*s++);
+}
+
+void printint(DoubleCell n, int base)
+{
+    static const char digit[] = "0123456789ABCDEF";
+
+    char *ptr = strbuf;
+    bool neg = n < 0;
+
+    if (neg)
+        n = -n;
+
+    do {
+        *ptr++ = digit[n % base];
+    } while ((n /= base));
+
+    if (neg)
+        serput('-');
+
+    do {
+        serput(*--ptr);
+    } while (ptr > strbuf);
+    serput(' ');
+}
+
+void initMCU()
+{
+    WDTCTL = WDTPW | WDTHOLD;
+    initGPIO();
+    initClock();
+    initUART();
+    SYSCFG0 = FRWPPW;
+}
+
+void initGPIO()
+{
+    // Unnecessary, but done by TI example
+    P1DIR = 0xFF; P2DIR = 0xFF;
+    P1REN = 0xFF; P2REN = 0xFF;
+    P1OUT = 0x00; P2OUT = 0x00;
+
+    // Set LED pins to outputs
+    P6DIR |= BIT0 | BIT1 | BIT2;
+    P6OUT |= BIT0 | BIT1 | BIT2;
+    P5DIR |= BIT5 | BIT6 | BIT7;
+    P5OUT |= BIT5 | BIT6 | BIT7;
+
+    // Setup buttons w/ pullups
+    P3DIR &= ~BIT4; P3REN |= BIT4; P3OUT |= BIT4;
+    P2DIR &= ~BIT3; P2REN |= BIT3; P2OUT |= BIT3;
+
+    // Allow GPIO configurations to be applied
+    PM5CTL0 &= ~LOCKLPM5;
+
+    // Safety measure, prevent unwarranted interrupts
+    P5IFG = 0;
+    P6IFG = 0;
+}
+
+void initClock()
+{
+    static_assert(MCLK_FREQ_MHZ == 16);
+
+    // Configure one FRAM waitstate as required by the device datasheet for MCLK
+    // operation beyond 8MHz _before_ configuring the clock system.
+    FRCTL0 = FRCTLPW | NWAITS_1;
+
+    P2SEL0 |= BIT0 | BIT1;                       // P2.0~P2.1: crystal pins
+    do
+    {
+        CSCTL7 &= ~(XT1OFFG | DCOFFG);           // Clear XT1 and DCO fault flag
+        SFRIFG1 &= ~OFIFG;
+    } while (SFRIFG1 & OFIFG);                   // Test oscillator fault flag
+
+    __bis_SR_register(SCG0);                     // disable FLL
+    CSCTL3 |= SELREF__XT1CLK;                    // Set XT1 as FLL reference source
+    CSCTL1 = DCOFTRIMEN_1 | DCOFTRIM0 | DCOFTRIM1 | DCORSEL_5;// DCOFTRIM=5, DCO Range = 16MHz
+    CSCTL2 = FLLD_0 + 487;                       // DCOCLKDIV = 16MHz
+    __delay_cycles(3);
+    __bic_SR_register(SCG0);                     // enable FLL
+    Software_Trim();                             // Software Trim to get the best DCOFTRIM value
+
+    CSCTL4 = SELMS__DCOCLKDIV | SELA__XT1CLK;    // set XT1 (~32768Hz) as ACLK source, ACLK = 32768Hz
+                                                 // default DCOCLKDIV as MCLK and SMCLK source
+
+}
+
+void initUART()
+{
+    // Configure UART pins
+    P5SEL0 |= BIT1 | BIT2;
+    SYSCFG3 |= USCIA0RMP; // Set the remapping source
+
+    UCA0CTLW0 |= UCSWRST;
+    UCA0CTLW0 |= UCSSEL__SMCLK; // 16 MHz
+
+    // Baud Rate calculation
+    // N = 16MHz / 115200 = 138.888
+    // OS16 = 1, UCBRx = INT(N/16) = 8(.6806)
+    // UCBRFx = INT( ((N/16) - UCBRx) * 16) = 10(.8896)
+    UCA0BRW = 8;
+    UCA0MCTLW = 0xD600 | 0x00A0 | UCOS16;
+
+    UCA0CTLW0 &= ~UCSWRST;                    // Initialize eUSCI
+}
+
+void Software_Trim()
+{
+    unsigned int oldDcoTap = 0xffff;
+    unsigned int newDcoTap = 0xffff;
+    unsigned int newDcoDelta = 0xffff;
+    unsigned int bestDcoDelta = 0xffff;
+    unsigned int csCtl0Copy = 0;
+    unsigned int csCtl1Copy = 0;
+    unsigned int csCtl0Read = 0;
+    unsigned int csCtl1Read = 0;
+    unsigned int dcoFreqTrim = 3;
+    unsigned char endLoop = 0;
+
+    do
+    {
+        CSCTL0 = 0x100;                         // DCO Tap = 256
+        do
+        {
+            CSCTL7 &= ~DCOFFG;                  // Clear DCO fault flag
+        }while (CSCTL7 & DCOFFG);               // Test DCO fault flag
+
+        __delay_cycles((unsigned int)3000 * MCLK_FREQ_MHZ);// Wait FLL lock status (FLLUNLOCK) to be stable
+                                                           // Suggest to wait 24 cycles of divided FLL reference clock
+        while((CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)) && ((CSCTL7 & DCOFFG) == 0));
+
+        csCtl0Read = CSCTL0;                   // Read CSCTL0
+        csCtl1Read = CSCTL1;                   // Read CSCTL1
+
+        oldDcoTap = newDcoTap;                 // Record DCOTAP value of last time
+        newDcoTap = csCtl0Read & 0x01ff;       // Get DCOTAP value of this time
+        dcoFreqTrim = (csCtl1Read & 0x0070)>>4;// Get DCOFTRIM value
+
+        if(newDcoTap < 256)                    // DCOTAP < 256
+        {
+            newDcoDelta = 256 - newDcoTap;     // Delta value between DCPTAP and 256
+            if((oldDcoTap != 0xffff) && (oldDcoTap >= 256)) // DCOTAP cross 256
+                endLoop = 1;                   // Stop while loop
+            else
+            {
+                dcoFreqTrim--;
+                CSCTL1 = (csCtl1Read & (~DCOFTRIM)) | (dcoFreqTrim<<4);
+            }
+        }
+        else                                   // DCOTAP >= 256
+        {
+            newDcoDelta = newDcoTap - 256;     // Delta value between DCPTAP and 256
+            if(oldDcoTap < 256)                // DCOTAP cross 256
+                endLoop = 1;                   // Stop while loop
+            else
+            {
+                dcoFreqTrim++;
+                CSCTL1 = (csCtl1Read & (~DCOFTRIM)) | (dcoFreqTrim<<4);
+            }
+        }
+
+        if(newDcoDelta < bestDcoDelta)         // Record DCOTAP closest to 256
+        {
+            csCtl0Copy = csCtl0Read;
+            csCtl1Copy = csCtl1Read;
+            bestDcoDelta = newDcoDelta;
+        }
+
+    }while(endLoop == 0);                      // Poll until endLoop == 1
+
+    CSCTL0 = csCtl0Copy;                       // Reload locked DCOTAP
+    CSCTL1 = csCtl1Copy;                       // Reload locked DCOFTRIM
+    while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)); // Poll until FLL is locked
+}
+
+// disables the watchdog between the __start() and the __crt_0init()
+extern "C"
+__attribute__((naked, section(".crt_0010init")))
+void __gcc_disable_watchdog()
+{
+    WDTCTL = WDTPW + WDTHOLD;
+}
+