aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <clyne@bitgloo.com>2023-11-26 18:51:01 -0500
committerClyne Sullivan <clyne@bitgloo.com>2023-11-26 18:51:01 -0500
commit4fe405dbb3cff8dcd5e3f9623a7a2ccf33af64b8 (patch)
tree274a65fa2170129cfa6a847a408a29b927a3e22a
parent1eefd5f51c228db8d29d64714521d5ea24e43b33 (diff)
add msp430 proof-of-concept
-rw-r--r--.gitignore1
-rw-r--r--compat.txt133
-rw-r--r--msp430.cpp353
3 files changed, 487 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 2ea588d..6dbd7b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
*.a
*.o
sprit
+msp430
diff --git a/compat.txt b/compat.txt
new file mode 100644
index 0000000..3a06bbb
--- /dev/null
+++ b/compat.txt
@@ -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
index 0000000..6c92f47
--- /dev/null
+++ b/msp430.cpp
@@ -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;
+}
+