add msp430 proof-of-concept

main
Clyne 1 year ago
parent 1eefd5f51c
commit 4fe405dbb3
Signed by: clyne
GPG Key ID: 3267C8EBF3F9AFC7

1
.gitignore vendored

@ -2,3 +2,4 @@
*.a
*.o
sprit
msp430

@ -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 ]

@ -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;
}
Loading…
Cancel
Save