Compare commits

..

1 Commits
master ... llvm

Author SHA1 Message Date
Clyne 114b825c35
wip: dictionary disassembly 1 year ago

1
.gitattributes vendored

@ -1 +0,0 @@
msp430/msp430fr2476.h linguist-vendored

5
.gitignore vendored

@ -1,13 +1,8 @@
.*
*.o
*.dat
*.bin
*.lzss
alee
alee-msp430
alee-standalone
libalee.a
core.fth.h
doc/
msp430/lzss
msp430/msp430fr2476_all.h

3
.gitmodules vendored

@ -1,3 +0,0 @@
[submodule "tests"]
path = tests
url = https://github.com/gerryjackson/forth2012-test-suite

2303
Doxyfile

File diff suppressed because it is too large Load Diff

@ -1,62 +1,49 @@
CXXFLAGS += -std=c++20 -g3 -ggdb -O0 \
CXXFLAGS += -std=c++17 -g3 -ggdb -O0 \
-pedantic -Wall -Wextra -Werror -Weffc++ -Wconversion \
-fno-exceptions -fno-rtti
-fno-exceptions -fno-threadsafe-statics -fno-rtti #-fstack-usage
CXXFILES := $(wildcard libalee/*.cpp)
OBJFILES := $(subst .cpp,.o,$(CXXFILES))
LIBFILE := libalee/libalee.a
STANDALONE := forth/core.fth
all: alee
msp430: CXX := msp430-elf-g++
msp430: AR := msp430-elf-gcc-ar
msp430: CXXFLAGS += -I. -I/usr/msp430-elf/usr/include
msp430: CXXFLAGS += -Os -mmcu=msp430fr2476 -ffunction-sections -fdata-sections
msp430: CXXFLAGS += -flto -fno-asynchronous-unwind-tables -fno-threadsafe-statics -fno-stack-protector
msp430: CXXFLAGS += -DALEE_MSP430_HOST
msp430: LDFLAGS += -L msp430 -T msp430fr2476.ld -Wl,-gc-sections -Wl,--no-warn-rwx-segments
msp430: msp430/alee-msp430
msp430-prep: CXXFLAGS += -DALEE_MSP430 -Imsp430
msp430-prep: msp430/msp430fr2476_all.h
msp430-prep: STANDALONE += forth/core-ext.fth forth/tools.fth forth/msp430.fth
msp430-prep: core.fth.h
msp430-prep: clean-lib
small: CXXFLAGS += -Os -fno-asynchronous-unwind-tables -fno-threadsafe-statics -fno-stack-protector
msp430: CXX := msp430-elf32-g++
msp430: AR := msp430-elf32-gcc-ar
msp430: CXXFLAGS += -I.
msp430: CXXFLAGS += -Os -mmcu=msp430g2553 -ffunction-sections -fdata-sections
msp430: CXXFLAGS += -DMEMDICTSIZE=200 -flto
msp430: LDFLAGS += -L/opt/msp430-elf32/include -Tmsp430/msp430g2553.ld -Wl,-gc-sections
msp430: clean-lib msp430/alee-msp430
small: CXXFLAGS += -Os
small: alee
fast: CXXFLAGS += -O3 -march=native -mtune=native -flto
fast: alee
standalone: core.fth.h
standalone: alee-standalone
alee: $(LIBFILE)
msp430/alee-msp430: $(LIBFILE)
alee-standalone: $(LIBFILE)
alee-standalone: core.fth.h $(LIBFILE)
cppcheck:
cppcheck --enable=warning,style,information --disable=missingInclude \
libalee alee*.cpp *dict.hpp
test: standalone
echo "bye" | ./alee-standalone forth/core-ext.fth tests/src/tester.fr tests/src/core.fr
echo "\nbye\n" | ./alee-standalone forth/core-ext.fth forth/test/tester.fr forth/test/core.fr
$(LIBFILE): $(OBJFILES)
$(AR) crs $@ $(OBJFILES)
core.fth.h: alee.dat
xxd -i $< > $@
sed -i "s/\[\]/\[ALEE_RODICTSIZE\]/" $@
alee.dat: alee $(STANDALONE)
echo "3 sys" | ./alee $(STANDALONE)
sed -i "s/unsigned /static const &/" $@
msp430/msp430fr2476_all.h:
$(MAKE) -C msp430
alee.dat: alee forth/core.fth
echo "3 sys" | ./alee forth/core.fth
clean: clean-lib
rm -f alee alee-standalone msp430/alee-msp430

@ -1,33 +1,41 @@
# Alee Forth
Alee Forth is a concise Forth implementation written in modern C++ that aims for portability, minimal memory footprint, and execution efficiency.
Alee is a concise Forth implementation written in modern C++ that aims for portability, minimal program size, and execution efficiency.
## Cross-platform compatibility
Alee Forth relies on the C++20 standard. It *does not* rely on any operating system. As a result, portability extends down to microcontroller targets with < 16kB flash and < 1 kB of RAM. See the `msp430` folder for an example of such a port.
Alee relies on the C++17 standard. Alee *does not* rely on operating-system-specific functions, making portability easy.
System-specific functionality is achieved through a `sys` Forth word. This word calls a user-supplied C++ function that implements whatever functionality is needed.
The goal of portability extends down to microcontroller targets with kilobytes of memory. See the `msp430` target for an example of a port.
System-specific functionality is obtained through a `sys` Forth word. This word calls a user-supplied C++ function that implements the necessary (or any additional) functionality.
## Forth compatibility
Alee Forth uses the [Forth 2012 test suite](https://github.com/gerryjackson/forth2012-test-suite) to ensure standards compliance. The entire "core" [word-set](https://forth-standard.org/standard/core) is implemented as well as most of the "core extension" word-set. The compiled program contains a minimal set of fundamental words with libraries in the `forth` directory supplying these larger word-sets. The "core" word-set can be compiled into the program by building the `standalone` target.
Alee implements a large majority of the "core" and "core extension" [word sets](https://forth-standard.org/standard/core). Implementation is tracked in `compat.txt`, with missing words listed below. Fundamental words are built into Alee (written in C++); the rest of the implementation is in `core.fth` and `core-ext.fth`.
Running Alee without `core.fth` or `core-ext.fth` passed as arguments will leave you with a minimal word set. The `standalone` target will package the `core.fth` dictionary into the program.
**Missing** core extension words:
**Missing** core features:
* Pictured numeric output conversion (e.g. `<# #>`)
**Missing** core extensions:
```
PARSE-NAME REFILL RESTORE-INPUT S\" SAVE-INPUT
.R HOLDS PAD PARSE PARSE-NAME REFILL RESTORE-INPUT S\" SAVE-INPUT SOURCE-ID U.R U> UNUSED WITHIN [COMPILE]
```
Alee aims for compliance with common Forth standards like Forth 2012 and ANS Forth. Compliance is tested using a [Forth 2012 test suite](https://github.com/gerryjackson/forth2012-test-suite). Supported test files are in the `test` directory, with tests for unimplemented words commented out.
## Building
Alee requires `make` and a compiler that supports C++20. Simply running `make` will produce the `libalee.a` library and a REPL binary named `alee`. The core word-sets can be passed into `alee` via the command line: `./alee forth/core.fth forth/core-ext.fth`.
Alee requires `make` and a C++17-compatible compiler. Simply running `make` will produce the `libalee.a` library and a REPL binary named `alee`. Note that this binary has no built-in libraries; these can be passed in by calling `./alee core.fth core-ext.fth`.
Other available build targets:
There are other build targets:
* `small`: Optimize for minimal binary size.
* `fast`: Optimize for maximum performance on the host system.
* `standalone`: Builds the core dictionary (`core.fth`) into the binary.
* `msp430-prep` and `msp430`: Builds a binary for the [MSP430G2553](https://www.ti.com/product/MSP430G2553) microcontroller. See the `msp430` folder for more information.
* `msp430`: Builds a binary for the [MSP430G2553](https://www.ti.com/product/MSP430G2553) microcontroller. The `standalone` target must be built first for the core dictionary.
If building for a new platform, review these files: `Makefile`, `libalee/types.hpp`, and `libalee/state.hpp`. It is possible to modify the implementation to use 32-bit words, but this will require re-writing the core word-sets.
If building for a new platform, see `Makefile`, `types.hpp`, and `state.hpp` for available configuration options.

@ -16,16 +16,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "libalee/alee.hpp"
#include "alee.hpp"
#include "splitmemdict.hpp"
#include <array>
#include <charconv>
#include <fstream>
#include <iostream>
#include <vector>
#define ALEE_RODICTSIZE
#include "core.fth.h"
static bool okay = false;
@ -36,8 +34,7 @@ static void parseFile(State&, std::istream&);
int main(int argc, char *argv[])
{
(void)alee_dat_len;
SplitMemDict<sizeof(alee_dat)> dict (alee_dat);
SplitMemDict<alee_dat_len> dict (alee_dat);
State state (dict, readchar);
std::vector args (argv + 1, argv + argc);
@ -92,8 +89,13 @@ void user_sys(State& state)
state.dict.read(Dictionary::Base));
std::cout << buf << ' ';
break;
case 1: // unused
state.push(static_cast<Addr>(state.dict.capacity() - state.dict.here()));
case 1: // u.
{
Addr ucell = static_cast<Addr>(state.pop());
std::to_chars(buf, buf + sizeof(buf), ucell,
state.dict.read(Dictionary::Base));
std::cout << buf << ' ';
}
break;
case 2: // emit
std::cout << static_cast<char>(state.pop());

@ -16,20 +16,17 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "libalee/alee.hpp"
#include "alee.hpp"
#include "memdict.hpp"
#include <algorithm>
#include <charconv>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <vector>
#ifdef ALEE_MSP430
#include "lzss.h"
static const
#include "msp430fr2476_all.h"
static Error findword(State&, Word);
#endif // ALEE_MSP430
static void compile(State&);
static bool okay = false;
@ -41,9 +38,6 @@ int main(int argc, char *argv[])
{
MemDict dict;
State state (dict, readchar);
#ifdef ALEE_MSP430
Parser::customParse = findword;
#endif // ALEE_MSP430
dict.initialize();
@ -100,8 +94,13 @@ void user_sys(State& state)
state.dict.read(Dictionary::Base));
std::cout << buf << ' ';
break;
case 1: // unused
state.push(static_cast<Addr>(state.dict.capacity() - state.dict.here()));
case 1: // u.
{
Addr ucell = static_cast<Addr>(state.pop());
std::to_chars(buf, buf + sizeof(buf), ucell,
state.dict.read(Dictionary::Base));
std::cout << buf << ' ';
}
break;
case 2: // emit
std::cout << static_cast<char>(state.pop());
@ -112,6 +111,9 @@ void user_sys(State& state)
case 4: // load
load(state);
break;
case 5: // compile
compile(state);
break;
default:
break;
}
@ -163,48 +165,37 @@ void parseFile(State& state, std::istream& file)
}
}
#ifdef ALEE_MSP430
#define LZSS_MAGIC_SEPARATOR (0xFB)
static char lzword[32];
static int lzwlen;
static char lzbuf[32];
static char *lzptr;
Error findword(State& state, Word word)
// Prints all compiled words, their start addresses, and their "disassembly".
// Hopefully, it won't be too difficult to translate these into LLVM IR.
void compile(State& state)
{
char *ptr = lzword;
for (auto it = word.begin(&state.dict); it != word.end(&state.dict); ++it) {
*ptr = *it;
if (islower(*ptr))
*ptr -= 32;
++ptr;
}
lzwlen = (int)(ptr - lzword);
lzptr = lzbuf;
lzssinit(msp430fr2476_all_lzss, msp430fr2476_all_lzss_len);
auto ret = decode([](int c) {
if (c != LZSS_MAGIC_SEPARATOR) {
*lzptr++ = (char)c;
} else {
if (lzwlen == lzptr - lzbuf - 2 && std::equal(lzbuf, lzptr - 2, lzword)) {
lzwlen = (*(lzptr - 2) << 8) | *(lzptr - 1);
return 1;
} else {
lzptr = lzbuf;
auto& dict = state.dict;
Addr latest = dict.latest();
Addr attr = 0;
do {
Addr oldlen = attr >> 6;
latest -= oldlen;
attr = dict.read(latest);
auto lw = Word::fromLength(latest + sizeof(Cell), attr & 0x1F);
if (!(attr & Dictionary::Immediate)) {
Addr start = dict.getexec(latest);
Addr len = oldlen;
len -= start;
len += latest;
std::for_each(lw.begin(&dict), lw.end(&dict), putchar);
std::cout << " @ " << start << std::endl;
for (Addr i = 0; i < len; i += sizeof(Cell)) {
Addr addr = start;
addr += i;
std::cout << '\t' << (Addr)dict.read(addr) << ' ';
}
std::cout << std::endl;
}
return 0;
});
if (ret == EOF) {
return Error::noword;
} else {
Parser::processLiteral(state, (Cell)lzwlen);
return Error::none;
}
} while (latest != Dictionary::Begin);
}
#endif // ALEE_MSP430

@ -0,0 +1,3 @@
#include "libalee/parser.hpp"
#include "libalee/state.hpp"

@ -0,0 +1,187 @@
6.1 Core words
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 *
yes 6.1.0100 */
yes 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 /
yes 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 >
yes 6.1.0550 >BODY
yes 6.1.0560 >IN
yes 6.1.0570 >NUMBER
yes 6.1.0580 >R
yes 6.1.0630 ?DUP
yes 6.1.0650 @
yes 6.1.0670 ABORT
yes 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
yes 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
yes 6.1.1170 DECIMAL
yes 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? (always false)
yes 6.1.1360 EVALUATE
yes 6.1.1370 EXECUTE
yes 6.1.1380 EXIT
yes 6.1.1540 FILL
yes 6.1.1550 FIND
yes 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 (as "imm")
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
yes 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
yes 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"
yes 6.1.2170 S>D
6.1.2210 SIGN
yes 6.1.2214 SM/REM
yes 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
yes 6.1.2320 U.
yes 6.1.2340 U<
yes 6.1.2360 UM*
yes 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 ]
6.2 Core extension words
yes 6.2.0200 .(
6.2.0210 .R
yes 6.2.0260 0<>
yes 6.2.0280 0>
yes 6.2.0340 2>R
yes 6.2.0410 2R>
yes 6.2.0415 2R@
yes 6.2.0455 :NONAME
yes 6.2.0500 <>
yes 6.2.0620 ?DO
yes 6.2.0698 ACTION-OF
yes 6.2.0700 AGAIN
yes 6.2.0825 BUFFER:
yes 6.2.0855 C"
yes 6.2.0873 CASE
yes 6.2.0945 COMPILE,
yes 6.2.1173 DEFER
yes 6.2.1175 DEFER!
yes 6.2.1177 DEFER@
yes 6.2.1342 ENDCASE
yes 6.2.1343 ENDOF
yes 6.2.1350 ERASE
yes 6.2.1485 FALSE
yes 6.2.1660 HEX
6.2.1675 HOLDS
yes 6.2.1725 IS
yes 6.2.1850 MARKER
yes 6.2.1930 NIP
yes 6.2.1950 OF
6.2.2000 PAD
6.2.2008 PARSE
6.2.2020 PARSE-NAME
yes 6.2.2030 PICK
6.2.2125 REFILL
6.2.2148 RESTORE-INPUT
yes 6.2.2150 ROLL
6.2.2266 S\"
6.2.2182 SAVE-INPUT
6.2.2218 SOURCE-ID
yes 6.2.2295 TO
yes 6.2.2298 TRUE
yes 6.2.2300 TUCK
6.2.2330 U.R
6.2.2350 U>
6.2.2395 UNUSED
yes 6.2.2405 VALUE
6.2.2440 WITHIN
6.2.2530 [COMPILE]
yes 6.2.2535 \

@ -1,8 +1,6 @@
-1 constant true
0 constant false
: unused 1 sys ;
: hex 16 base ! ;
: nip swap drop ;
@ -10,68 +8,42 @@
: 0> 0 > ;
: 0<> 0= 0= ;
: u> swap u< ;
: within over - >r - r> swap u> ;
: 2r@ ['] r> , ['] r> , ['] 2dup , ['] >r , ['] >r , ['] swap , ; imm
: compile, postpone literal postpone execute ;
: [compile] bl word find -1 = if , else compile, then ; imm
: \ _source @ >in @ +
begin dup c@ while 0 over c! char+ repeat drop ; imm
: again postpone repeat ; imm
: ?do ['] _lit , here 0 , ['] >r , ['] 2dup , postpone 2>r
['] = , postpone if postpone leave postpone then
here ; imm
: .( [char] ) word count type ; imm
: c" state @ if ['] _jmp , here 0 , then
[char] " here char+ begin
key dup 3 pick <> while
over c! char+ repeat drop
swap drop here - here c! here
state @ 0= if exit then
dup count nip 1+ allot
here rot !
postpone literal ; imm
: buffer: create allot ;
: value constant ;
: to ' 4 cells + state @ if postpone literal ['] ! , else ! then ; imm
: defer create ['] exit , does> @ execute ;
: defer@ >body @ ;
: defer! >body ! ;
: is state @ if postpone ['] postpone defer! else ' defer! then ; imm
: compile, postpone literal postpone execute ;
: \ _source @ >in @ +
begin dup c@ while 0 over c! char+ repeat drop ; imm
: again postpone repeat ; imm
: ?do ['] 2dup , ['] _lit , here 0 , ['] >r , ['] = , postpone if
['] 2drop , postpone 2r> ['] drop , ['] >r , ['] exit ,
postpone then postpone 2>r here ; imm
: .( [char] ) word count type ; imm
: c" state @ if ['] _jmp , here 0 , then
[char] " word
state @ 0= if exit then
dup count nip allot
here rot !
postpone literal ; imm
: buffer: create allot ;
: value constant ;
: to ' 4 cells + state @ if postpone literal ['] ! , else ! then ; imm
: defer create does> @ execute ;
: defer@ >body @ ;
: defer! >body ! ;
: is state @ if postpone ['] postpone defer! else ' defer! then ; imm
: action-of state @ if postpone ['] postpone defer@ else ' defer@ then ; imm
: erase 0 fill ;
: erase begin dup 0 > while swap 0 over ! 1+ swap 1- repeat ;
: roll dup if swap >r 1- recurse r> swap exit then drop ;
: marker here _latest @ create , , does>
dup @ _latest ! cell+ @ here - allot ;
: case 0 ; imm
: of ['] over , ['] = , postpone if ['] drop , ; imm
: endof postpone else ; imm
: endcase ['] drop , begin ?dup while postpone then repeat ; imm
: holds begin dup while 1- 2dup + c@ hold repeat 2drop ;
: .r over dup 0< if 1 else 0 then
begin 1+ swap base @ / dup 0<> while swap repeat
drop - spaces . ;
: u.r over 0 begin 1+ swap 0 base @ _/ dup 0<> while swap repeat
drop - spaces u. ;
( WORD uses HERE and must be at least 33 characters. )
: pad here [ 50 chars ] literal + align ;
: parse here dup >r swap begin
key? if key else dup then 2dup <> while
rot dup >r c! r> char+ swap repeat
2drop r> tuck - ;
: marker create _latest @ , here , does>
dup @ _latest ! cell+ @ here swap - allot ;
: source-id _source @ _begin < if 0 else -1 then ;
: case ['] _lit , 1 here 0 , ['] drop , ; imm
: of ['] over , ['] = , postpone if ; imm
: endof ['] _jmp , here >r 0 , postpone then
swap 1+ swap r> tuck ! ; imm
: endcase swap 0 do dup @ swap here swap ! loop drop ['] drop , ; imm

@ -6,50 +6,38 @@
: cell+ 2 + ;
: cells 2 * ;
: char+ 1 + ;
: chars ;
: . 0 sys ;
: u. 1 sys ;
: emit 2 sys ;
: 1+ 1 + ;
: 1- 1 - ;
: over 1 pick ;
: rot >r swap r> swap ;
: -rot rot rot ;
: ' _' drop ;
: ! 1 _! ;
: @ 1 _@ ;
: +! dup >r swap r> @ + swap ! ;
: base 0 ;
: here 1 cells @ ;
: allot 1 cells +! ;
: _latest 2 cells ;
: imm _latest @ dup @ 1 5 << | swap ! ;
: immediate imm ;
: state 3 cells ;
: _source 4 cells ;
: _sourceu 5 cells ;
: >in 6 cells ;
: [ 0 3 cells ! ; imm
: ] 1 3 cells ! ;
: , here ! 1 cells allot ;
: , 1 cells dup >r @ ! r> dup +! ;
: [ 0 state ! ; imm
: ] 1 state ! ;
: literal [ ' _lit dup , , ] , , ; imm
: ['] ' [ ' literal , ] ; imm
: base 0 ;
: here [ 1 cells ] literal @ ;
: allot [ 1 cells ] literal +! ;
: state [ 3 cells ] literal ;
: _compxt [ 4 cells ] literal ;
: _source [ 5 cells ] literal ;
: _sourceu [ 6 cells ] literal ;
: >in [ 7 cells ] literal ;
: _begin [ 8 cells 80 chars + ] literal ;
: c! 0 _! ;
: c@ 0 _@ ;
: c, here c! 1 allot ;
: if ['] _jmp0 , here 0 , ; imm
: then here swap ! ; imm
: else ['] _jmp , here 0 , swap here swap ! ; imm
@ -58,11 +46,21 @@
1 = swap ['] _lit , , if ['] execute ,
else ['] , , then ; imm
: over 1 pick ;
: rot >r swap r> swap ;
: -rot rot rot ;
: 2drop drop drop ;
: 2dup over over ;
: 2over 3 pick 3 pick ;
: 2swap rot >r rot r> ;
: c! 0 _! ;
: c@ 0 _@ ;
: c, here c! 1 allot ;
: char+ 1+ ;
: chars ;
: decimal 10 base ! ;
: 2r> ['] r> , ['] r> , ['] swap , ; imm
@ -85,23 +83,22 @@
: do ['] _lit , here 0 , ['] >r , postpone 2>r here ; imm
: unloop postpone 2r> ['] 2drop , ['] r> , ['] drop , ; imm
: leave postpone 2r> ['] 2drop , ['] exit , ; imm
: +loop ['] r> , ['] 2dup , ['] + ,
postpone r@ ['] swap , ['] >r ,
['] - , ['] 2dup , ['] + , ['] over , ['] ^ ,
['] rot , ['] rot , ['] ^ , ['] & , ['] _lit , 0 ,
['] < , ['] _jmp0 , ,
postpone unloop here 1 cells - swap ! ; imm
: leave postpone 2r> ['] 2drop , postpone 2r>
['] drop , ['] >r , ['] exit , ; imm
: +loop postpone 2r> ['] 2dup , ['] swap , ['] < , ['] >r ,
['] rot , ['] + , ['] 2dup , ['] swap , ['] < ,
['] r> , ['] ^ , ['] -rot ,
postpone 2>r ['] _jmp0 , ,
postpone unloop here swap ! ; imm
: loop postpone 2r> ['] 1+ , ['] 2dup ,
postpone 2>r ['] = , ['] _jmp0 , ,
postpone unloop here 1 cells - swap ! ; imm
postpone unloop here swap ! ; imm
: i postpone r@ ; imm
: j postpone 2r> ['] r> , postpone r@ ['] swap ,
['] >r , ['] -rot , postpone 2>r ; imm
: aligned dup [ 1 cells 1- ] literal swap over & if [ 1 cells ] literal
swap - + else drop then ;
: align here dup aligned swap - allot ;
: align here 1 cells 1- swap over & if 1 cells swap - allot else drop then ;
: aligned dup 1 cells 1- swap over & if 1 cells swap - + else drop then ;
: and & ;
: or | ;
@ -111,7 +108,7 @@
: invert -1 ^ ;
: mod % ;
: 2* 2 * ;
: _msb [ 1 1 cells 8 * 1- << ] literal ;
: _msb 1 1 cells 8 * 1- << ;
: 2/ dup 1 >> swap 0< if _msb or then ;
: /mod 2dup % -rot / ;
@ -134,26 +131,22 @@
: min 2dup <= if drop else swap drop then ;
: max 2dup <= if swap drop else drop then ;
: source _source @ _sourceu @ ;
: source _source @ 0 begin 2dup + c@ while char+ repeat ;
: key _source @ >in @ +
begin dup c@ 0 = while _in repeat
c@ 1 >in +! ;
: key? _source @ >in @ + c@ 0 <> ;
: word begin key? if key else -1 then 2dup <> until
key? 0= if 2drop 0 here c! here exit then
here begin char+ swap over c! swap
key? if key else dup then
2dup <> while rot repeat
2drop here - here c! here ;
: word here dup >r char+ >r
begin key? if key 2dup <> else 0 0 then while
r> swap over c! char+ >r repeat
2drop r> r> swap over - 1- over c! ;
: count dup char+ swap c@ ;
: char 0 here char+ c! bl word char+ c@ ;
: char bl word char+ c@ ;
: [char] char postpone literal ; imm
: ( begin [char] ) key <> while repeat ; imm
: _type >r begin dup 0 > while
swap dup c@ r@ execute char+ swap 1- repeat 2drop r> drop ;
: type [ ' emit ] literal _type ;
: type begin dup 0 > while swap dup c@ emit char+ swap 1- repeat 2drop ;
: s" state @ if ['] _jmp , here 0 , then
[char] " word count
state @ 0= if exit then
@ -162,19 +155,21 @@
swap postpone literal postpone literal ; imm
: ." postpone s" state @ if ['] type , else type then ; imm
: :noname here dup _compxt ! 0 , here swap ] ;
: create : here [ 4 cells ] literal + postpone literal postpone ; 0 , ;
: create align here
1 cells 1 chars - allot
bl word count swap drop
1 chars allot
swap over over ! swap allot align
['] _lit , here 3 cells + , ['] exit dup , ,
dup @ 31 & over _latest @ - 6 << or over ! _latest ! ;
: _does> _latest @ dup @ 31 & + cell+ aligned 2 cells +
['] _jmp over ! cell+
r@ 1 cells - @ swap ! ;
: does> ['] _jmp , here 2 cells + dup , 2 cells + ,
['] _does> , ['] exit , ; imm
: >body cell+ @ ;
: _does> >r _latest @ dup @ 31 & + cell+ aligned [ 2 cells ] literal +
['] _jmp over ! cell+ r> cell+ swap ! ;
: does> state @ if
['] _lit , here 2 cells + , ['] _does> , ['] exit , else
here dup _does> dup _compxt ! 0 , ] then ; imm
: variable create [ 1 cells ] literal allot ;
: variable create 1 cells allot ;
: constant create , does> @ ;
: quit begin _rdepth 1 > while r> drop repeat postpone [ ;
@ -183,7 +178,7 @@
postpone if ['] type , ['] abort ,
postpone else ['] 2drop , postpone then ; imm
: recurse _compxt @ dup @ 31 & + cell+ aligned , ; imm
: recurse depth 1- pick dup @ 31 & + cell+ aligned , ; imm
: move dup 0 <= if drop 2drop exit then
>r 2dup < r> swap if
@ -200,7 +195,9 @@
: accept over >r begin dup 0 > while
key dup 32 < if 2drop 0
else dup emit rot 2dup c! char+ swap drop swap 1- then
repeat drop r> - [ 1 chars ] literal / ;
repeat drop r> - 1 chars / ;
: :noname 0 , here ] ;
: evaluate _source @ >r _sourceu @ >r >in @ >r
0 >in ! _sourceu ! _source ! _ev
@ -220,15 +217,3 @@
>r dup c@ swap >r base @ swap
dup _isdigit - _uma
r> char+ r> 1- repeat ;
: <# 40 here c! ;
: #> 2drop here dup c@ + 40 here c@ - ;
: hold -1 here +! here dup c@ + c! ;
: # base @
>r 0 i um/mod r> swap >r um/mod r>
rot 9 over <
if 7 + then 48 + hold ;
: #s begin # 2dup or 0= until ;
: sign 0< if [char] - hold then ;
: u. 0 <# bl hold #s #> type ;

@ -1,97 +0,0 @@
: vector! 10 sys ;
: byte! 11 sys ;
: byte@ 12 sys ;
: reg! 13 sys ;
: reg@ 14 sys ;
: sr+ 15 sys ;
: sr- 16 sys ;
: lpm-exit 17 sys ;
: reg [ ' reg@ ' reg! ] literal literal ;
: byte [ ' byte@ ' byte! ] literal literal ;
: set ( b r reg/byte -- )
>r over r> execute >r rot r> | -rot execute ;
: clear ( b r reg/byte -- )
>r over r> execute >r rot invert r> & -rot execute ;
: toggle ( b r reg/byte -- )
>r over r> execute >r rot r> ^ -rot execute ;
create _outs p1out , p2out , p3out , p4out , p5out , p6out ,
create _ins p1in , p2in , p3in , p4in , p5in , p6in ,
create _dirs p1dir , p2dir , p3dir , p4dir , p5dir , p6dir ,
1 constant output
0 constant input
: pin-mode ( output? pin port -- )
rot >r cells _dirs + @ byte r> if set else clear then ;
: pin-set ( high? pin port -- )
rot >r cells _outs + @ byte r> if set else clear then ;
: pin-get ( pin port -- high? )
cells _ins + @ byte@ swap and 0 > ;
: analog-init
adcon adcsht_2 or adcctl0 reg set
adcshp adcctl1 reg set
adcres adcctl2 reg clear
adcres_2 adcctl2 reg set
adcie0 adcie reg set ;
: rtc-init
rtcps__10 rtcctl reg! ;
: ms ( u -- )
rtcmod reg!
rtcss_3 rtcsr or rtcctl reg set
begin rtciv reg@ 0<> until
rtc-init ;
: D0 bit5 1 ;
: D1 bit6 1 ;
: D2 bit1 2 ;
: D3 bit4 1 ;
: D4 bit7 2 ;
: D5 bit0 3 ;
: D6 bit1 3 ;
: D7 bit7 3 ;
: D8 bit6 3 ;
: D9 bit5 3 ;
: D10 bit4 4 ;
: D11 bit2 2 ;
: D12 bit6 2 ;
: D13 bit5 2 ;
: A0 bit0 0 ;
: A1 bit1 0 ;
: A2 bit5 0 ;
: A3 bit6 0 ;
: A4 bit2 0 ;
: A5 bit3 0 ;
: AREF bit4 0 ;
: pin-analog
drop
dup p1sel0 reg set
p1sel1 reg set ;
: analog-get
drop 0 begin
swap 2/ dup 0<> while
swap 1+ repeat
drop adcmctl0 reg!
adcenc adcsc or adcctl0 reg set
adcmem0 reg@ ;
: LED1R bit1 5 ;
: LED1G bit0 5 ;
: LED1B bit2 5 ;
: LED2R bit6 4 ;
: LED2G bit5 4 ;
: LED2B bit7 4 ;
: SW2 bit3 1 ;
: SW3 bit4 2 ;

File diff suppressed because it is too large Load Diff

@ -0,0 +1,66 @@
\ From: John Hayes S1I
\ Subject: tester.fr
\ Date: Mon, 27 Nov 95 13:10:09 PST
\ (C) 1995 JOHNS HOPKINS UNIVERSITY / APPLIED PHYSICS LABORATORY
\ MAY BE DISTRIBUTED FREELY AS LONG AS THIS COPYRIGHT NOTICE REMAINS.
\ VERSION 1.2
\ 24/11/2015 Replaced Core Ext word <> with = 0=
\ 31/3/2015 Variable #ERRORS added and incremented for each error reported.
\ 22/1/09 The words { and } have been changed to T{ and }T respectively to
\ agree with the Forth 200X file ttester.fs. This avoids clashes with
\ locals using { ... } and the FSL use of }
HEX
\ SET THE FOLLOWING FLAG TO TRUE FOR MORE VERBOSE OUTPUT; THIS MAY
\ ALLOW YOU TO TELL WHICH TEST CAUSED YOUR SYSTEM TO HANG.
VARIABLE VERBOSE
FALSE VERBOSE !
\ TRUE VERBOSE !
: EMPTY-STACK \ ( ... -- ) EMPTY STACK: HANDLES UNDERFLOWED STACK TOO.
DEPTH ?DUP IF DUP 0< IF NEGATE 0 DO 0 LOOP ELSE 0 DO DROP LOOP THEN THEN ;
VARIABLE #ERRORS 0 #ERRORS !
: ERROR \ ( C-ADDR U -- ) DISPLAY AN ERROR MESSAGE FOLLOWED BY
\ THE LINE THAT HAD THE ERROR.
CR TYPE SOURCE TYPE \ DISPLAY LINE CORRESPONDING TO ERROR
EMPTY-STACK \ THROW AWAY EVERY THING ELSE
#ERRORS @ 1 + #ERRORS !
\ QUIT \ *** Uncomment this line to QUIT on an error
;
VARIABLE ACTUAL-DEPTH \ STACK RECORD
CREATE ACTUAL-RESULTS 20 CELLS ALLOT
: T{ \ ( -- ) SYNTACTIC SUGAR.
;
: -> \ ( ... -- ) RECORD DEPTH AND CONTENT OF STACK.
DEPTH DUP ACTUAL-DEPTH ! \ RECORD DEPTH
?DUP IF \ IF THERE IS SOMETHING ON STACK
0 DO ACTUAL-RESULTS I CELLS + ! LOOP \ SAVE THEM
THEN ;
: }T \ ( ... -- ) COMPARE STACK (EXPECTED) CONTENTS WITH SAVED
\ (ACTUAL) CONTENTS.
DEPTH ACTUAL-DEPTH @ = IF \ IF DEPTHS MATCH
DEPTH ?DUP IF \ IF THERE IS SOMETHING ON THE STACK
0 DO \ FOR EACH STACK ITEM
ACTUAL-RESULTS I CELLS + @ \ COMPARE ACTUAL WITH EXPECTED
= 0= IF S" INCORRECT RESULT: " ERROR LEAVE THEN
LOOP
THEN
ELSE \ DEPTH MISMATCH
S" WRONG NUMBER OF RESULTS: " ERROR
THEN ;
: TESTING \ ( -- ) TALKING COMMENT.
SOURCE VERBOSE @
IF DUP >R TYPE CR R> >IN !
ELSE >IN ! DROP [CHAR] * EMIT
THEN ;

@ -1,13 +0,0 @@
: .s depth dup 0 ?do dup i - pick . loop drop ;
: ? @ . ;
: dump hex 0 do i cells over + @ s>d <# # # # # bl hold #> type loop
drop decimal ;
: words _latest @ begin
dup @ dup 31 &
2 pick cell+ \ lt l len ws
2 pick 6 >> 1023 < if \ lt l len ws
rot 6 >> else \ lt len ws adv
>r cell+ rot drop r> @ then
-rot swap type space \ lt adv
over _begin <> while - repeat 2drop ;

@ -1,7 +0,0 @@
#include "config.hpp"
#include "corewords.hpp"
#include "ctype.hpp"
#include "dictionary.hpp"
#include "parser.hpp"
#include "state.hpp"
#include "types.hpp"

@ -1,5 +0,0 @@
#ifndef ALEE_MSP430_HOST
#define LIBALEE_SECTION
#else
#define LIBALEE_SECTION __attribute__((section(".libalee")))
#endif

@ -16,187 +16,216 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "alee.hpp"
#include "corewords.hpp"
#include "parser.hpp"
#include <cstring>
#include <utility>
static void find(State&, Word);
static DoubleCell popd(State&);
static void pushd(State&, DoubleCell);
Word getword(State& state)
{
auto word = state.dict.input();
while (word.size() == 0) {
state.input(state);
word = state.dict.input();
}
return word;
}
void newdef(State& state, Word word)
{
auto& dict = state.dict;
auto addr = dict.alignhere();
dict.addDefinition(word);
state.push(addr);
};
void find(State& state, Word word)
{
if (auto j = state.dict.find(word); j > 0) {
state.push(state.dict.getexec(j));
auto imm = state.dict.read(j) & Dictionary::Immediate;
state.push(imm ? 1 : -1);
} else if (auto i = CoreWords::findi(state, word); i >= 0) {
state.push(i);
state.push(i == CoreWords::Semicolon ? 1 : -1);
} else {
state.push(0);
state.push(0);
}
}
LIBALEE_SECTION
void CoreWords::run(Cell ins, State& state)
{
Cell cell;
DoubleCell dcell;
Addr index = ins;
auto& ip = state.ip();
auto popd = [](State& s) {
DoubleCell dcell = s.pop();
dcell <<= sizeof(Cell) * 8;
dcell |= static_cast<Addr>(s.pop());
return dcell;
};
auto pushd = [](State& s, DoubleCell d) {
s.push(static_cast<Cell>(d));
s.push(static_cast<Cell>(d >> (sizeof(Cell) * 8)));
};
execute:
if (index >= Dictionary::Begin) {
// must be calling a defined subroutine
state.pushr(ip);
ip = index;
state.pushr(state.ip);
state.ip = index;
return;
} else switch (index) {
case token("_lit"): // Execution semantics of `literal`.
case 0: // _lit
state.push(state.beyondip());
break;
case token("drop"):
case 1: // drop
state.pop();
break;
case token("dup"):
case 2: // dup
state.push(state.top());
break;
case token("swap"):
case 3: // swap
std::swap(state.top(), state.pick(1));
break;
case token("pick"):
case 4: // pick
state.push(state.pick(state.pop()));
break;
case token("sys"): // Calls user-defined "system" handler.
case 5: // sys
user_sys(state);
break;
case token("+"):
case 6: // add
cell = state.pop();
state.top() += cell;
break;
case token("-"):
case 7: // sub
cell = state.pop();
state.top() -= cell;
break;
case token("m*"): // ( n n -- d )
case 8: // mul ( n n -- d )
cell = state.pop();
dcell = state.pop() * cell;
pushd(state, dcell);
break;
case token("_/"): // ( d n -- n )
case 9: // div ( d n -- n )
cell = state.pop();
dcell = popd(state);
state.push(static_cast<Cell>(dcell / cell));
break;
case token("_%"): // ( d n -- n )
case 10: // mod ( d n -- n )
cell = state.pop();
dcell = popd(state);
state.push(static_cast<Cell>(dcell % cell));
break;
case token("_@"): // ( addr cell? -- n )
case 11: // peek
if (state.pop())
state.push(state.dict.read(state.pop()));
else
state.push(state.dict.readbyte(state.pop()));
break;
case token("_!"): // ( n addr cell? -- )
case 12: // poke
cell = state.pop();
if (auto addr = state.pop(); cell)
state.dict.write(addr, state.pop());
else
state.dict.writebyte(addr, state.pop() & 0xFFu);
break;
case token(">r"):
case 13: // pushr
state.pushr(state.pop());
break;
case token("r>"):
case 14: // popr
state.push(state.popr());
break;
case token("="):
case 15: // equal
cell = state.pop();
state.top() = state.top() == cell ? -1 : 0;
break;
case token("<"):
case 16: // lt
cell = state.pop();
state.top() = state.top() < cell ? -1 : 0;
break;
case token("&"):
case 17: // and
cell = state.pop();
state.top() &= cell;
break;
case token("|"):
case 18: // or
cell = state.pop();
state.top() |= cell;
break;
case token("^"):
case 19: // xor
cell = state.pop();
state.top() ^= cell;
break;
case token("<<"):
case 20: // shl
cell = state.pop();
reinterpret_cast<Addr&>(state.top()) <<= static_cast<Addr>(cell);
break;
case token(">>"):
case 21: // shr
cell = state.pop();
reinterpret_cast<Addr&>(state.top()) >>= static_cast<Addr>(cell);
break;
case token(":"): // Begins definition/compilation of new word.
state.push(state.dict.alignhere());
state.dict.write(Dictionary::CompToken, state.top());
while (!state.dict.hasInput())
state.input();
state.dict.addDefinition(state.dict.input());
case 22: // colon
newdef(state, getword(state));
state.compiling(true);
break;
case token("_'"): // Collects input word and finds execution token.
while (!state.dict.hasInput())
state.input();
find(state, state.dict.input());
case 23: // tick
find(state, getword(state));
break;
case token("execute"):
case 24: // execute
index = state.pop();
goto execute;
case token("exit"):
ip = state.popr();
state.verify(ip != 0, Error::exit);
case 25: // exit
state.ip = state.popr();
if (state.ip == 0)
std::longjmp(state.jmpbuf, static_cast<int>(Error::exit));
break;
case token(";"): // Concludes word definition.
state.dict.add(token("exit"));
case 26: // semic
state.dict.add(findi("exit"));
state.compiling(false);
cell = state.pop();
dcell = cell - state.dict.latest();
if (dcell >= Dictionary::MaxDistance) {
// Large distance to previous entry: store in dedicated cell.
state.dict.write(static_cast<Addr>(cell) + sizeof(Cell),
static_cast<Cell>(dcell));
dcell = Dictionary::MaxDistance;
}
dcell = (cell - state.dict.latest()) << 6;
state.dict.write(cell,
(state.dict.read(cell) & 0x1F) | static_cast<Cell>(dcell << 6));
(state.dict.read(cell) & 0x1F) | static_cast<Cell>(dcell));
state.dict.latest(cell);
break;
case token("_jmp0"): // Jump if popped value equals zero.
case 27: // _jmp0
if (state.pop()) {
state.beyondip();
break;
}
[[fallthrough]];
case token("_jmp"): // Unconditional jump.
ip = state.beyondip();
case 28: // _jmp
state.ip = state.beyondip();
return;
case token("depth"):
case 29: // depth
state.push(static_cast<Cell>(state.size()));
break;
case token("_rdepth"):
case 30: // _rdepth
state.push(static_cast<Cell>(state.rsize()));
break;
case token("_in"): // Fetches more input from the user input source.
state.input();
case 31: // _in
state.input(state);
break;
case token("_ev"): // Evaluates words from current input source.
case 32: // _ex
{
const auto st = state.save();
ip = 0;
state.ip = 0;
Parser::parseSource(state);
state.load(st);
}
break;
case token("find"):
case 33: // find
cell = state.pop();
find(state,
Word::fromLength(static_cast<Addr>(cell + 1),
state.dict.readbyte(cell)));
break;
case token("_uma"): // ( d u u -- d ): Unsigned multiply-add.
case 34: // _uma
{
const auto plus = state.pop();
cell = state.pop();
@ -206,12 +235,12 @@ execute:
pushd(state, dcell);
}
break;
case token("u<"):
case 35: // u<
cell = state.pop();
state.top() = static_cast<Addr>(state.top()) <
static_cast<Addr>(cell) ? -1 : 0;
break;
case token("um/mod"):
case 36: // um/mod
cell = state.pop();
dcell = popd(state);
@ -222,48 +251,43 @@ execute:
static_cast<DoubleAddr>(dcell) /
static_cast<Addr>(cell)));
break;
default: // Compacted literals (WordCount <= ins < Begin).
default:
state.push(ins - WordCount);
break;
}
ip += sizeof(Cell);
state.ip += sizeof(Cell);
}
LIBALEE_SECTION
Cell CoreWords::findi(State& state, Word word)
template<typename Iter>
Cell findi(Iter it, std::size_t size)
{
return findi(word.begin(&state.dict), word.size());
}
auto ptr = CoreWords::wordsarr;
Cell wordsi = 0;
LIBALEE_SECTION
void find(State& state, Word word)
{
Cell tok = 0;
Cell imm = 0;
while (ptr < CoreWords::wordsarr + sizeof(CoreWords::wordsarr)) {
auto end = ptr;
while (*end)
++end;
if (auto j = state.dict.find(word); j > 0) {
tok = state.dict.getexec(j);
imm = (state.dict.read(j) & Dictionary::Immediate) ? 1 : -1;
} else if (tok = CoreWords::findi(state, word); tok >= 0) {
imm = (tok == CoreWords::token(";")) ? 1 : -1;
std::size_t wordsize = end - ptr;
if (wordsize == size && Dictionary::equal(ptr, end, it))
return wordsi;
++wordsi;
ptr = end + 1;
}
state.push(tok);
state.push(imm);
return -1;
}
DoubleCell popd(State& s)
Cell CoreWords::findi(const char *word)
{
DoubleCell dcell = s.pop();
dcell <<= sizeof(Cell) * 8;
dcell |= static_cast<Addr>(s.pop());
return dcell;
return ::findi(word, strlen(word));
}
void pushd(State& s, DoubleCell d)
Cell CoreWords::findi(State& state, Word word)
{
s.push(static_cast<Cell>(d));
s.push(static_cast<Cell>(d >> (sizeof(Cell) * 8)));
return ::findi(word.begin(&state.dict), word.size());
}

@ -1,78 +1,51 @@
//
/// @file corewords.hpp
/// @brief Manages the fundamental word-set and its execution.
//
// Alee Forth: A portable and concise Forth implementation in modern C++.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/**
* Alee Forth: A portable and concise Forth implementation in modern C++.
* Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ALEEFORTH_COREWORDS_HPP
#define ALEEFORTH_COREWORDS_HPP
#include "config.hpp"
#include "dictionary.hpp"
#include "types.hpp"
#include <algorithm>
class State;
#include "state.hpp"
/**
* To be implemented by the user, this function is called when the `sys` word
* is executed.
* @param state Current execution state object.
*/
void user_sys(State& state);
void user_sys(State&);
/**
* @class CoreWords
* @brief Provides the fundamental word-set and manages its execution.
*/
class CoreWords
{
public:
/**
* Searches for the token/index of the given word if it is part of the
* fundamental word-set.
* @param state Current execution state object.
* @param word Word (stored in state's dictionary memory) to look up.
* @return The token/index of the word or -1 if not found.
*/
static Cell findi(State& state, Word word);
constexpr static Cell WordCount = 37;
constexpr static Cell Semicolon = 26;
/**
* Looks up the token/index of the given fundamental word.
* Primarily used for compile-time lookup.
* @param word The word to look up.
* @return The token/index of the word or -1 if not found.
* Finds execution token that corresponds to the given word.
* Returns -1 if not found.
*/
consteval static Cell token(const char *word) {
return findi(word, strlen(word));
}
static Cell findi(const char *);
static Cell findi(State&, Word);
/**
* Executes the given execution token using the given state.
* @param token Any valid execution token (word, fundamental, constant...).
* @param state The state object to execute with.
* Executes the given CoreWord execution token using the given state.
*/
static void run(Cell token, State& state);
static void run(Cell, State&);
/**
* String lookup table for the fundamental word-set.
* This also determines the opcode (index) of these words.
*/
constexpr static char wordsarr[] =
"_lit\0drop\0dup\0swap\0pick\0sys\0"
"+\0-\0m*\0_/\0_%\0"
@ -82,37 +55,6 @@ public:
"exit\0;\0_jmp0\0_jmp\0"
"depth\0_rdepth\0_in\0_ev\0find\0"
"_uma\0u<\0um/mod\0";
/**
* Count of total fundamental words.
*/
constexpr static Cell WordCount = [] {
return std::count(wordsarr, wordsarr + sizeof(wordsarr), '\0'); }();
private:
/**
* Generic implementation of findi(). Private; use public implementations.
* @param it Beginning iterator of the word to search for.
* @param size Size of the searched-for word i.e. end == it + size.
* @return The token/index of the word or -1 if not found.
*/
template<typename Iter>
LIBALEE_SECTION
constexpr static Cell findi(Iter it, std::size_t size)
{
const char *ptr = CoreWords::wordsarr;
for (Cell wordsi = 0; wordsi < WordCount; ++wordsi) {
std::size_t wordsize = strlen(ptr);
if (wordsize == size && Dictionary::equal(ptr, ptr + wordsize, it))
return wordsi;
ptr += wordsize + 1;
}
return -1;
}
};
#endif // ALEEFORTH_COREWORDS_HPP

@ -0,0 +1,36 @@
/**
* Alee Forth: A portable and concise Forth implementation in modern C++.
* Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ctype.hpp"
bool isspace(uint8_t c) {
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
}
bool isdigit(uint8_t c) {
return c >= '0' && c <= '9';
}
bool isalpha(uint8_t c) {
return isupper(c) || (c >= 'a' && c <= 'z');
}
bool isupper(uint8_t c) {
return c >= 'A' && c <= 'Z';
}

@ -1,59 +1,34 @@
//
/// @file ctype.hpp
/// @brief Simple implementations of character comparison functions.
//
// Alee Forth: A portable and concise Forth implementation in modern C++.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/**
* Alee Forth: A portable and concise Forth implementation in modern C++.
* Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ALEEFORTH_CTYPE_HPP
#define ALEEFORTH_CTYPE_HPP
#include <cstdint>
/** Determines the length of a null-terminated string. */
constexpr inline unsigned strlen(const char * const s) {
unsigned i = 0;
while (s[i]) i++;
return i;
}
/** Tests if given character represents whitespace. */
constexpr inline bool isspace(uint8_t c) {
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
}
/**
* We implement our own character comparison functions to keep them lean.
*/
/** Tests if given character is a numerical digit. */
constexpr inline bool isdigit(uint8_t c) {
return c >= '0' && c <= '9';
}
/** Tests if given character is an uppercase letter. */
constexpr inline bool isupper(uint8_t c) {
return c >= 'A' && c <= 'Z';
}
/** Tests if given character is a lowercase letter. */
constexpr inline bool islower(uint8_t c) {
return c >= 'a' && c <= 'z';
}
#include <cstdint>
/** Tests if given character is a letter. */
constexpr inline bool isalpha(uint8_t c) {
return isupper(c) || (c >= 'a' && c <= 'z');
}
bool isspace(uint8_t);
bool isdigit(uint8_t);
bool isalpha(uint8_t);
bool isupper(uint8_t);
#endif // ALEEFORTH_CTYPE_HPP

@ -16,9 +16,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "alee.hpp"
#include "ctype.hpp"
#include "dictionary.hpp"
#include <cstring>
LIBALEE_SECTION
void Dictionary::initialize()
{
write(Base, 10);
@ -28,7 +30,6 @@ void Dictionary::initialize()
write(Source, Input + sizeof(Cell));
}
LIBALEE_SECTION
Addr Dictionary::allot(Cell amount) noexcept
{
Addr old = here();
@ -37,157 +38,119 @@ Addr Dictionary::allot(Cell amount) noexcept
if (neww < capacity()) {
write(Here, static_cast<Addr>(neww));
} else {
// TODO how to handle allot failure? Error code?
// TODO
}
return old;
}
LIBALEE_SECTION
void Dictionary::add(Cell value) noexcept
{
write(allot(sizeof(Cell)), value);
}
LIBALEE_SECTION
Addr Dictionary::aligned(Addr addr)
Addr Dictionary::aligned(Addr addr) const noexcept
{
return (addr + (sizeof(Cell) - 1)) & ~(sizeof(Cell) - 1);
Addr unaligned = addr & (sizeof(Cell) - sizeof(uint8_t));
if (unaligned) {
addr += sizeof(Cell);
addr -= unaligned;
}
return addr;
}
LIBALEE_SECTION
Addr Dictionary::alignhere() noexcept
{
here(aligned(here()));
return here();
}
LIBALEE_SECTION
void Dictionary::addDefinition(Word word) noexcept
{
Cell wsize = word.size();
add(wsize);
if (alignhere() - latest() >= MaxDistance)
add(0);
auto addr = allot(wsize);
auto it = word.begin(this);
const auto end = word.end(this);
while (it != end)
writebyte(addr++, *it++);
for (auto w = word.start; w != word.wend; ++w)
writebyte(allot(1), readbyte(w));
alignhere();
}
LIBALEE_SECTION
Addr Dictionary::find(Word word) noexcept
{
Addr lt = latest();
for (;;) {
const Addr l = read(lt);
const Addr len = l & 0x1F;
Word lw;
lw.start = lt + sizeof(Cell);
lw.wend = lw.start + len;
if ((l >> 6) < MaxDistance) {
lw = Word::fromLength(lt + sizeof(Cell), len);
if (equal(word, lw))
return lt;
else if (lt == Begin)
break;
else
lt -= l >> 6;
} else {
lw = Word::fromLength(lt + 2 * sizeof(Cell), len);
if (equal(word, lw))
return lt;
else if (lt == Begin)
break;
else
lt -= static_cast<Addr>(read(lt + sizeof(Cell)));
}
if (equal(word, lw))
return lt;
else if (lt == Begin)
break;
else
lt -= l >> 6;
}
return 0;
}
LIBALEE_SECTION
Addr Dictionary::getexec(Addr addr) noexcept
{
const Addr l = read(addr);
const Addr len = l & 0x1Fu;
const Addr len = read(addr) & 0x1Fu;
addr += sizeof(Cell);
if ((l >> 6) == MaxDistance)
addr += sizeof(Cell);
addr += len;
return aligned(addr);
}
LIBALEE_SECTION
bool Dictionary::hasInput() const noexcept
{
const Addr src = read(Dictionary::Source);
const Addr end = read(Dictionary::SourceLen);
auto idx = static_cast<uint8_t>(read(Dictionary::Input));
while (idx < end) {
auto ch = readbyte(src + idx);
if (ch == '\0') {
break;
} else if (!isspace(ch)) {
return true;
}
++idx;
}
return false;
}
LIBALEE_SECTION
Word Dictionary::input() noexcept
{
const Addr src = read(Dictionary::Source);
const Addr end = read(Dictionary::SourceLen);
auto idx = static_cast<uint8_t>(read(Dictionary::Input));
uint8_t idx = read(Dictionary::Input) & 0xFFu;
Addr wstart = src + idx;
Addr wend = wstart;
Word word;
word.start = src + idx;
word.wend = word.start;
while (idx < end) {
auto ch = readbyte(wend);
auto ch = readbyte(word.wend);
if (isspace(ch)) {
if (wend - wstart > 0)
if (word.size() > 0)
break;
++wstart;
++word.start;
} else if (ch == '\0') {
break;
}
++wend;
++word.wend;
++idx;
}
writebyte(Dictionary::Input, ++idx);
return Word(wstart, wend);
return word;
}
LIBALEE_SECTION
bool Dictionary::equal(Word word, const char *str, unsigned len) const noexcept
{
return word.size() == len && equal(word.begin(this), word.end(this), str);
return word.size() == len &&
equal(word.begin(this), word.end(this), str);
}
LIBALEE_SECTION
bool Dictionary::equal(Word word, Word other) const noexcept
{
return word.size() == other.size() && equal(word.begin(this), word.end(this), other.begin(this));
return word.size() == other.size() &&
equal(word.begin(this), word.end(this), other.begin(this));
}
bool Dictionary::eqchars(char c1, char c2)
{
return c1 == c2 ||
(isalpha(c1) && isalpha(c2) && (c1 | 32) == (c2 | 32));
}

@ -1,230 +1,136 @@
//
/// @file dictionary.hpp
/// @brief Defines the dictionary interface and common functionality.
//
// Alee Forth: A portable and concise Forth implementation in modern C++.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/**
* Alee Forth: A portable and concise Forth implementation in modern C++.
* Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ALEEFORTH_DICTIONARY_HPP
#define ALEEFORTH_DICTIONARY_HPP
#include "config.hpp"
#include "types.hpp"
#include "ctype.hpp"
#include <algorithm>
#include <cstddef>
#include <cstdint>
/**
* @class Dictionary
* @brief Provides an interface and essential funcitonality for a dictionary.
* @details The core read and write functionality is left virtual so that
* dictionaries can be stored in any medium. So, this class cannot be used
* directly; the programmer must define a dictionary class that inherits this
* one.
*
* Dictionary entry format (for a 16-bit implementation):
* - One information cell:
* - bits 0..4: Length of name
* - bit 5: Set if word is immediate
* - bits 6..15: Distance (backwards) to the next entry
* - If bits 6..15 are all one-bits then "long" distance in following cell.
* - "Length" bytes of name
* - Zero or more bytes for address alignment
* - Zero or more bytes of the definition's contents
* Dictionary entry format:
* - 1 information byte
* bits 0..4: Length of name (L)
* bit 5: Immediate?
* bits 6..15: Distance to next entry (negative)
* - L bytes of name
* - 0+ bytes for address alignment
* - 0+ bytes of entry's data...
*/
class Dictionary
{
public:
/** Stores Numerical base to use for input/output. */
/**
* The beginning of the dictionary is used for "internal" variables.
*/
constexpr static Addr Base = 0;
/** Stores the current `here` address. */
constexpr static Addr Here = sizeof(Cell);
/** Stores the address of the most recently defined word. */
constexpr static Addr Latest = sizeof(Cell) * 2;
/** Stores a boolean indication of compiling state. */
constexpr static Addr Compiling = sizeof(Cell) * 3;
/** Stores the address of the last execution token determined by colon. */
constexpr static Addr CompToken = sizeof(Cell) * 4;
/** Stores the address of the current interpreter input source. */
constexpr static Addr Source = sizeof(Cell) * 5;
/** Stores the size in bytes of the interpreter input source. */
constexpr static Addr SourceLen = sizeof(Cell) * 6;
/** Stores the dictionary's input buffer (a counted string). */
constexpr static Addr Input = sizeof(Cell) * 7;
/** Stores the size of the dictionary's input buffer in bytes. */
constexpr static Addr InputCells = 80;
/** Stores the dictionary's "beginning" i.e. where new definitions begin. */
constexpr static Addr Begin = sizeof(Cell) * 8 + InputCells;
/** "Immediate" marker bit for a word's definition. */
constexpr static Addr Source = sizeof(Cell) * 4;
constexpr static Addr SourceLen = sizeof(Cell) * 5;
constexpr static Addr Input = sizeof(Cell) * 6; // len data...
constexpr static Addr InputCells = 80; // bytes!
constexpr static Addr Begin = sizeof(Cell) * 7 + InputCells;
constexpr static Cell Immediate = (1 << 5);
/** Maximum "short" distance between two definitions. */
constexpr static Cell MaxDistance = (1 << (sizeof(Cell) * 8 - 6)) - 1;
/** Returns the value of the cell at the given address. */
/**
* Dictionary data can be stored on any read-write interface.
* You must create a dictionary class that inherits Dictionary and
* implement these functions. See `memdict.hpp` for a simple block-of-
* memory implementation.
*/
virtual Cell read(Addr) const noexcept = 0;
/** Writes the given value to the cell at the given address. */
virtual void write(Addr, Cell) noexcept = 0;
/** Returns the byte stored at the given address. */
virtual uint8_t readbyte(Addr) const noexcept = 0;
/** Writes the given byte to the given address. */
virtual void writebyte(Addr, uint8_t) noexcept = 0;
/** Returns the total capacity of the dictionary in bytes. */
virtual unsigned long int capacity() const noexcept = 0;
/**
* Initializes essential dictionary values.
* Must be called before dictionary use.
* Does initial dictionary setup, required before use for execution.
*/
void initialize();
/**
* Gets the address stored in `here`.
*/
LIBALEE_SECTION
Addr here() const noexcept { return read(Here); }
/**
* Sets the address stored in `here`.
*/
LIBALEE_SECTION
void here(Addr l) noexcept { write(Here, l); }
/**
* Gets the value of `latest`.
*/
LIBALEE_SECTION
Addr latest() const noexcept { return read(Latest); }
/**
* Sets the value of `latest`.
*/
LIBALEE_SECTION
void latest(Addr l) noexcept { write(Latest, l); }
/**
* Aligns the given address to the next Cell boundary if necessary.
* @param addr The address to align.
* @return The resulting aligned address.
*/
static Addr aligned(Addr addr);
/**
* Aligns `here` to the next Cell boundary if necessary.
* @return The new aligned address stored in `here`.
*/
// Aligns the given address.
Addr aligned(Addr) const noexcept;
// Aligns `here`.
Addr alignhere() noexcept;
// Advances `here` by the given number of bytes.
Addr allot(Cell) noexcept;
// Stores value to `here`, then adds sizeof(Cell) to `here`.
void add(Cell) noexcept;
/**
* Allocates memory by returning and then increasing the current `here`.
* @param count The number of bytes to increase `here` by.
* @return The address stored in `here` before the increase.
*/
Addr allot(Cell count) noexcept;
/**
* Stores the given value to `here` then calls allot to "save" that cell.
* @param value The value to store.
* @see allot(Cell)
*/
void add(Cell value) noexcept;
/**
* Stores the beginning of a new word definition in the dictionary.
* The word must eventually have its definition concluded via semicolon.
* @param word The dictionary-stored name of the new word.
* Uses add() to store a new definition entry starting at `here`.
* The entry does not become active until a semicolon is executed.
*/
void addDefinition(Word word) noexcept;
void addDefinition(Word) noexcept;
/**
* Searches the dictionary for an entry for the given word.
* @param word The dictionary-stored word to search for.
* @return The beginning address of the word or zero if not found.
* Returns zero if not found.
*/
Addr find(Word word) noexcept;
Addr find(Word) noexcept;
/**
* Produces the execution token for the given dictionary entry.
* @param addr The beginning address of a defined word.
* @return The execution token for the given word.
* @see find(Word)
* Given the address of a dictionary entry, produces the execution token
* for that entry.
*/
Addr getexec(Addr addr) noexcept;
Addr getexec(Addr) noexcept;
/**
* Reads the next word from the input buffer.
* @return The next word or an empty word if one is not available.
* Returns an empty word if the buffer is empty or entirely read.
*/
Word input() noexcept;
/**
* Returns true if the dictionary's input buffer has immediately available
* data.
*/
bool hasInput() const noexcept;
/**
* Checks if the dictionary-stored word is equivalent to the given string.
* @param word Dictionary-stored word to compare against.
* @param str String to compare to.
* @param size Size of the string to compare to.
* @return True if the two words are equivalent.
* Checks if this dictionary's word is equivalent to the given string/size.
*/
bool equal(Word word, const char *str, unsigned size) const noexcept;
bool equal(Word, const char *, unsigned) const noexcept;
/**
* Checks if two words stored in this dictionary are equivalent.
* @param word1 First word to compare
* @param word2 Second word to compare
* @return True if the words are equivalent.
* Checks if two words in this dictionary's word are equivalent.
*/
bool equal(Word word1, Word word2) const noexcept;
bool equal(Word, Word) const noexcept;
/**
* Generic equality comparison using our own case-insensitive comparator.
* Arguments and return value identical to std::equal.
*/
// Used for case-insensitive comparison between two iterators.
template<typename Iter1, typename Iter2>
LIBALEE_SECTION
constexpr static bool equal(Iter1 b1, Iter1 e1, Iter2 b2) {
static bool equal(Iter1 b1, Iter1 e1, Iter2 b2) {
return std::equal(b1, e1, b2, eqchars);
}
virtual ~Dictionary() {};
virtual ~Dictionary() = default;
private:
/**
* Case-insensitive character comparison used for dictionary lookup.
* @return True if the characters are equivalent.
*/
LIBALEE_SECTION
constexpr static bool eqchars(char c1, char c2) {
if (isalpha(static_cast<uint8_t>(c1)))
c1 |= 32;
if (isalpha(static_cast<uint8_t>(c2)))
c2 |= 32;
return c1 == c2;
}
// Case-insensitive comparison.
static bool eqchars(char c1, char c2);
};
#endif // ALEEFORTH_DICTIONARY_HPP

@ -16,63 +16,57 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "alee.hpp"
#include "corewords.hpp"
#include "ctype.hpp"
#include "parser.hpp"
Error (*Parser::customParse)(State&, Word) = nullptr;
LIBALEE_SECTION
Error Parser::parse(State& state, const char *str)
{
auto addr = Dictionary::Input;
// Set source and input length
const auto len = static_cast<Cell>(strlen(str));
Cell len = 0;
for (auto ptr = str; *ptr; ++ptr)
++len;
state.dict.write(addr, 0);
state.dict.write(Dictionary::SourceLen, len);
// Fill input buffer with string contents
addr += sizeof(Cell);
while (*str)
state.dict.writebyte(addr++, *str++);
// Zero the remaining input buffer
while (addr < Dictionary::Input + Dictionary::InputCells)
state.dict.writebyte(addr++, '\0');
return parseSource(state);
}
LIBALEE_SECTION
Error Parser::parseSource(State& state)
{
auto err = Error::none;
auto word = state.dict.input();
while (word.size() > 0) {
if (auto ret = parseWord(state, word); ret != Error::none)
return ret;
while (err == Error::none && state.dict.hasInput())
err = parseWord(state, state.dict.input());
word = state.dict.input();
}
return err;
return Error::none;
}
LIBALEE_SECTION
Error Parser::parseWord(State& state, Word word)
{
bool imm;
Addr ins;
Addr ins = state.dict.find(word);
// Search order: dictionary, core word-set, number, custom parse.
ins = state.dict.find(word);
if (ins == 0) {
auto cw = CoreWords::findi(state, word);
if (cw < 0) {
auto r = parseNumber(state, word);
if (r != Error::none)
return customParse ? customParse(state, word) : r;
else
return r;
return parseNumber(state, word);
} else {
ins = cw;
imm = ins == CoreWords::token(";");
imm = ins == CoreWords::Semicolon;
}
} else {
imm = state.dict.read(ins) & Dictionary::Immediate;
@ -87,21 +81,19 @@ Error Parser::parseWord(State& state, Word word)
return Error::none;
}
LIBALEE_SECTION
Error Parser::parseNumber(State& state, Word word)
{
const auto base = state.dict.read(Dictionary::Base);
DoubleCell result = 0;
auto it = word.begin(&state.dict);
auto i = word.start;
bool inv;
char c;
bool inv = *it == '-';
if (inv)
++it;
const auto end = word.end(&state.dict);
for (uint8_t c; it != end; ++it) {
c = *it;
c = state.dict.readbyte(i);
if (inv = c == '-'; inv)
c = state.dict.readbyte(++i);
do {
if (isdigit(c)) {
result *= base;
result += c - '0';
@ -111,33 +103,29 @@ Error Parser::parseNumber(State& state, Word word)
} else {
return Error::noword;
}
}
if (++i < word.wend)
c = state.dict.readbyte(i);
} while (i < word.wend);
if (inv)
result *= -1;
processLiteral(state, static_cast<Cell>(result));
return Error::none;
}
LIBALEE_SECTION
void Parser::processLiteral(State& state, Cell value)
{
auto value = static_cast<Cell>(result);
if (state.compiling()) {
constexpr auto ins = CoreWords::token("_lit");
auto ins = CoreWords::findi("_lit");
// Literal compression: opcodes between WordCount and Begin are unused,
// so we assign literals to them to save space. Opcode "WordCount"
// pushes zero to the stack, "WordCount + 1" pushes a one, etc.
const Cell maxlit = Dictionary::Begin - CoreWords::WordCount;
if (value >= 0 && value < maxlit)
value += CoreWords::WordCount;
else
if (value >= 0 && value < maxlit) {
state.dict.add(value + CoreWords::WordCount);
} else {
state.dict.add(ins);
state.dict.add(value);
state.dict.add(value);
}
} else {
state.push(value);
}
return Error::none;
}

@ -1,86 +1,55 @@
//
/// @file parser.hpp
/// @brief Provides functions to parse text for interpretation/execution.
//
// Alee Forth: A portable and concise Forth implementation in modern C++.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/**
* Alee Forth: A portable and concise Forth implementation in modern C++.
* Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ALEEFORTH_PARSER_HPP
#define ALEEFORTH_PARSER_HPP
#include "config.hpp"
#include "types.hpp"
#include "state.hpp"
#include <string_view>
/**
* @class Parser
* @brief Provides routines for parsing Forth code.
*/
class Parser
{
public:
/**
* Pointer to a user-provided function that
*/
static Error (*customParse)(State&, Word);
/**
* Parses and evaluates the given string using the given state.
* The string is stored in the state's input buffer before parseSource()
* is called.
* @param state The state to parse and evaluate with.
* @param str The string to parse.
* @return Error token to indicate if parsing was successful.
* @see parseSource(State&)
*/
static Error parse(State& state, const char *str);
/**
* Parses through and compiles or evaluates the words stored in the state's
* input source.
* @param state The state to parse with.
* @return Error token to indicate if parsing was successful.
* @see parseWord(State&, Word)
* Parses (and evaluates) the given string using the given state.
* The string is stored in the state's input buffer, then parseSource()
* works through that using parseWord(). parseWord() will compile or
* execute as necessary.
*/
static Error parseSource(State& state);
static Error parse(State&, const char *);
/**
* Parses the given value and either pushes it to the stack or compiles
* that functionality.
* @param state The state to give the value to.
* @param value The value to process.
* Parses (and evaluates) through the words stored in the state's input
* buffer.
*/
static void processLiteral(State& state, Cell value);
static Error parseSource(State&);
private:
/**
* Parses the given word using the given state.
* @return Error token to indicate if parsing was successful.
*/
static Error parseWord(State&, Word);
/**
* Attempts to parse the given word into a number.
* @param state The state object with the dictionary containing the word.
* @param word The dictionary-stored word (number) to parse.
* @return Error token to indicate if parsing was successful.
*/
static Error parseNumber(State& state, Word word);
static Error parseNumber(State&, Word);
};
#endif // ALEEFORTH_PARSER_HPP

@ -16,49 +16,50 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "alee.hpp"
#include "corewords.hpp"
#include "state.hpp"
#include <cstring>
#include <iterator>
LIBALEE_SECTION
bool State::compiling() const
{
return dict.read(Dictionary::Compiling);
}
LIBALEE_SECTION
void State::compiling(bool yes)
{
dict.write(Dictionary::Compiling, yes);
}
LIBALEE_SECTION
State::Context State::save()
std::pair<Addr, std::jmp_buf> State::save()
{
return context;
std::pair<Addr, std::jmp_buf> st;
st.first = ip;
std::memcpy(st.second, jmpbuf, sizeof(std::jmp_buf));
return st;
}
LIBALEE_SECTION
void State::load(const State::Context& ctx)
void State::load(const std::pair<Addr, std::jmp_buf>& st)
{
context = ctx;
ip = st.first;
std::memcpy(jmpbuf, st.second, sizeof(std::jmp_buf));
}
LIBALEE_SECTION
Error State::execute(Addr addr)
{
auto stat = static_cast<Error>(setjmp(context.jmpbuf));
auto stat = static_cast<Error>(setjmp(jmpbuf));
if (stat == Error::none) {
CoreWords::run(addr, *this);
if (context.ip >= Dictionary::Begin) {
if (ip >= Dictionary::Begin) {
// longjmp will exit this loop.
for (;;)
CoreWords::run(dict.read(context.ip), *this);
CoreWords::run(dict.read(ip), *this);
} else {
// addr was a CoreWord, all done now.
context.ip = 0;
ip = 0;
}
} else if (stat == Error::exit) {
stat = Error::none;
@ -67,7 +68,6 @@ Error State::execute(Addr addr)
return stat;
}
LIBALEE_SECTION
void State::reset()
{
while (size())
@ -76,16 +76,14 @@ void State::reset()
popr();
dict.write(Dictionary::Compiling, 0);
context.ip = 0;
ip = 0;
}
LIBALEE_SECTION
std::size_t State::size() const noexcept
{
return dsp - dstack;
}
LIBALEE_SECTION
std::size_t State::rsize() const noexcept
{
return rsp - rstack;

@ -1,80 +1,66 @@
//
/// @file state.hpp
/// @brief Provides object to manage execution and interpretation state.
//
// Alee Forth: A portable and concise Forth implementation in modern C++.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/**
* Alee Forth: A portable and concise Forth implementation in modern C++.
* Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ALEEFORTH_STATE_HPP
#define ALEEFORTH_STATE_HPP
#include "config.hpp"
#include "dictionary.hpp"
#include "types.hpp"
#include <csetjmp>
#include <cstddef>
#include <tuple>
/**
* Size of the primary data stack, number of cells.
*/
constexpr unsigned DataStackSize = 64;
/**
* Size of the return stack, number of cells.
*/
constexpr unsigned ReturnStackSize = 64;
constexpr unsigned DataStackSize = 16;
constexpr unsigned ReturnStackSize = 16;
/**
* @class State
* Object to track execution state.
*/
class State
{
/** Input functions should add input to the input buffer when available. */
using InputFunc = void (*)(State&);
/** Context object that defines a state of execution. */
struct Context {
Addr ip = 0; /** Instruction pointer */
std::jmp_buf jmpbuf = {}; /** setjmp() buffer for exiting execute() */
};
public:
/** Reference to dictionary used by this state. */
Addr ip = 0;
Dictionary& dict;
void (*input)(State&); // User-provided function to collect "stdin" input.
std::jmp_buf jmpbuf = {}; // Used when catching execution errors.
constexpr State(Dictionary& d, void (*i)(State&)):
dict(d), input(i) {}
bool compiling() const;
void compiling(bool);
/**
* Constructs a state object that uses the given dictionary and input
* function.
* @param d The dictionary to be used by this state
* @param i The input collection function to be used by this state
* Saves execution state so that a new execution can begin.
* Used for EVALUATE.
*/
constexpr State(Dictionary& d, InputFunc i):
dict(d), inputfunc(i), context() {}
std::pair<Addr, std::jmp_buf> save();
/**
* Begins execution starting from the given execution token.
* Reloads the given execution state.
*/
void load(const std::pair<Addr, std::jmp_buf>&);
/**
* Begins execution at the given execution token.
* If the token is a CoreWord, this function exits after its execution.
* Otherwise, execution continues until the word's execution completes.
* Encountering an error will cause this function to exit immediately.
* @param addr The token to be executed
* @return An error token to indicate if execution was successful
*/
Error execute(Addr addr);
Error execute(Addr);
/**
* Clears the data and return stacks, sets ip to zero, and clears the
@ -82,123 +68,56 @@ public:
*/
void reset();
/** Returns a reference to the instruction pointer. */
LIBALEE_SECTION
Addr& ip() noexcept {
return context.ip;
}
/** Calls the user input function with this state as the argument. */
LIBALEE_SECTION
void input() noexcept {
inputfunc(*this);
}
/** Returns true if currently in a compiling state. */
bool compiling() const;
/** Sets the compiling state. True if compiling, false if interpreting. */
void compiling(bool);
/** Returns the number of values stored on the data stack. */
std::size_t size() const noexcept;
/** Returns the number of values stored on the return stack. */
std::size_t rsize() const noexcept;
/**
* Returns the current execution state. Usually followed by a load() call.
*/
Context save();
/**
* Reloads the given execution state.
*/
void load(const Context&);
/**
* Pushes the given value to the data stack.
*/
LIBALEE_SECTION
inline void push(Cell value) {
verify(dsp < dstack + DataStackSize, Error::push);
if (dsp == dstack + DataStackSize)
std::longjmp(jmpbuf, static_cast<int>(Error::push));
*dsp++ = value;
}
/**
* Pops a value from the data stack and returns that value.
*/
LIBALEE_SECTION
inline Cell pop() {
verify(dsp > dstack, Error::pop);
if (dsp == dstack)
std::longjmp(jmpbuf, static_cast<int>(Error::pop));
return *--dsp;
}
/**
* Pushes the given value to the return stack.
*/
LIBALEE_SECTION
inline void pushr(Cell value) {
verify(rsp < rstack + ReturnStackSize, Error::pushr);
if (rsp == rstack + ReturnStackSize)
std::longjmp(jmpbuf, static_cast<int>(Error::pushr));
*rsp++ = value;
}
/**
* Pops a value from the return stack and returns that value.
*/
LIBALEE_SECTION
inline Cell popr() {
verify(rsp > rstack, Error::popr);
if (rsp == rstack)
std::longjmp(jmpbuf, static_cast<int>(Error::popr));
return *--rsp;
}
/**
* Returns the value stored at the current data stack position.
*/
LIBALEE_SECTION
inline Cell& top() {
verify(dsp > dstack, Error::top);
if (dsp == dstack)
std::longjmp(jmpbuf, static_cast<int>(Error::top));
return *(dsp - 1);
}
/**
* Picks a value currently stored on the data stack.
* @param i Index from current position to fetch from
* @return The value stored at the given index
*/
LIBALEE_SECTION
inline Cell& pick(std::size_t i) {
verify(dsp - i > dstack, Error::pick);
if (dsp - i == dstack)
std::longjmp(jmpbuf, static_cast<int>(Error::pick));
return *(dsp - i - 1);
}
/**
* Advances the instruction pointer and returns that cell's contents.
*/
LIBALEE_SECTION
// Advances the instruction pointer and returns that cell's contents.
inline Cell beyondip() {
context.ip += sizeof(Cell);
return dict.read(context.ip);
}
/**
* Asserts the given condition is true, longjmp-ing if false.
* Used as an exception handler and the method of exiting execution.
* @param condition Condition to be tested
* @param error Error code to report via longjmp() on false condition
*/
LIBALEE_SECTION
inline void verify(bool condition, Error error) {
if (!condition)
std::longjmp(context.jmpbuf, static_cast<int>(error));
ip += sizeof(Cell);
return dict.read(ip);
}
private:
InputFunc inputfunc; /** User-provided function to collect user input. */
Context context; /** State's current execution context. */
Cell dstack[DataStackSize] = {}; /** Data stack */
Cell rstack[ReturnStackSize] = {}; /** Return stack */
Cell *dsp = dstack; /** Current data stack position */
Cell *rsp = rstack; /** Current return stack position */
Cell dstack[DataStackSize] = {};
Cell rstack[ReturnStackSize] = {};
Cell *dsp = dstack;
Cell *rsp = rstack;
};
#endif // ALEEFORTH_STATE_HPP

@ -16,50 +16,36 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "alee.hpp"
#include "dictionary.hpp"
#include "types.hpp"
LIBALEE_SECTION
Addr Word::size() const noexcept
{
return wend - start;
}
LIBALEE_SECTION
Word::iterator Word::begin(const Dictionary *dict)
{
return iterator(start, dict);
}
LIBALEE_SECTION
Word::iterator Word::end(const Dictionary *dict)
{
return iterator(wend, dict);
}
LIBALEE_SECTION
Word::iterator& Word::iterator::operator++()
{
addr++;
return *this;
}
LIBALEE_SECTION
Word::iterator Word::iterator::operator++(int)
{
const auto copy = *this;
addr++;
return copy;
}
LIBALEE_SECTION
Word::iterator::value_type Word::iterator::operator*()
{
return dict->readbyte(addr);
}
LIBALEE_SECTION
bool Word::iterator::operator!=(const iterator& other)
{
return dict != other.dict || addr != other.addr;
}

@ -1,22 +1,20 @@
//
/// @file types.hpp
/// @brief Defines common types used throughout Alee Forth.
//
// Alee Forth: A portable and concise Forth implementation in modern C++.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/**
* Alee Forth: A portable and concise Forth implementation in modern C++.
* Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ALEEFORTH_TYPES_HPP
#define ALEEFORTH_TYPES_HPP
@ -24,86 +22,53 @@
#include <cstdint>
#include <iterator>
/** Dictionary address type. Must be equivalent to "unsigned Cell". */
/**
* Configure the below three types to match your platform.
*/
using Addr = uint16_t;
/** Data cell type. Dictionary is basically an array of this type. */
using Cell = int16_t;
/** Double-width cell type. Must be twice the size of Cell. */
using DoubleCell = int32_t;
/** Double-width addr type. Must be twice the size of Addr. Used by um/mod. */
using DoubleAddr = uint32_t;
using DoubleAddr = uint32_t; // Only used for um/mod.
struct Dictionary;
struct State;
/**
* Error enum to report success or failure of parsing or execution.
*/
using Func = void (*)(State&);
enum class Error : int {
none = 0, /** No error */
push, /** Could not push (data stack overflow) */
pop, /** Could not pop (data stack underflow) */
pushr, /** Could not push (return stack overflow) */
popr, /** Could not pop (return stack underflow) */
top, /** Could not fetch data stack top (data stack underflow) */
pick, /** Could not pick data stack value (data stack underflow) */
exit, /** No error, exited from State::execute() */
noword /** Parsing failed because the word was not found */
none = 0,
push,
pop,
pushr,
popr,
top,
pick,
exit,
noword
};
/**
* @class Word
* Stores the beginning and end indices of a dictionary-defined word.
* Stores the start and (past-the-)end addresses of a dictionary's word.
*/
class Word
struct Word
{
/** Beginning (inclusive) index */
Addr start;
/** End (exclusive) index */
Addr wend;
public:
struct iterator;
/**
* Constructs a word with the given start and end indices.
* @param s Start/beginning index
* @param e (past-the-)end index
*/
constexpr explicit Word(Addr s = 0, Addr e = 0):
start(s), wend(e) {}
/**
* Constructs a word using beginning index and length.
* @param s Beginning/start index of word
* @param l Count of bytes until end of word
* @return Resulting Word object
*/
LIBALEE_SECTION
static constexpr Word fromLength(Addr s, Addr l) {
return Word(s, s + l);
}
/** Returns the size of this word in bytes. */
Addr size() const noexcept;
/**
* Creates a beginning iterator for the word.
* @param dict Pointer to dictionary object containing this word
* @return Iterator pointing to this word's beginning
*/
iterator begin(const Dictionary *dict);
/**
* Creates an end iterator for the word.
* @param dict Pointer to dictionary object containing this word
* @return Iterator pointing to past-the-end of this word
*/
iterator end(const Dictionary *dict);
/**
* Forward-iterator for iterating through the letters of this word.
*/
// Iterators provided for std::equal.
struct iterator;
iterator begin(const Dictionary *);
iterator end(const Dictionary *);
struct iterator {
using iterator_category = std::input_iterator_tag;
using value_type = uint8_t;
@ -111,26 +76,14 @@ public:
using reference = void;
using difference_type = Cell;
/** Iterator's current address within its containing dictionary. */
Addr addr;
/** Pointer to dictionary that contains this word. */
const Dictionary *dict;
/**
* Constructs a word iterator.
* @param a The address the iterator points to
* @param d The dictionary that contains this word
*/
constexpr iterator(Addr a, const Dictionary *d):
addr(a), dict(d) {}
/** Prefix increment */
iterator& operator++();
/** Postfix increment */
iterator operator++(int);
/** Returns value pointed to by iterator */
value_type operator*();
/** Iterator comparison function (case-insensitive) */
bool operator!=(const iterator&);
};
};

@ -1,67 +1,52 @@
//
/// @file memdict.hpp
/// @brief Simple dictionary implementation using a large memory block.
//
// Alee Forth: A portable and concise Forth implementation in modern C++.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/**
* Alee Forth: A portable and concise Forth implementation in modern C++.
* Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ALEEFORTH_MEMDICT_HPP
#define ALEEFORTH_MEMDICT_HPP
#include "libalee/alee.hpp"
#include "alee.hpp"
#ifndef MEMDICTSIZE
/** Default dictionary size in bytes. */
#define MEMDICTSIZE (65536)
#endif
/** Size in bytes of a MemDict. */
constexpr unsigned long int MemDictSize = MEMDICTSIZE;
/**
* @class MemDict
* Dictionary implementation that uses a large block of memory.
*/
class MemDict : public Dictionary
{
/** Block of memory to contain dictionary's contents. */
uint8_t dict[MemDictSize] = {0};
public:
/** Returns the value of the cell at the given address. */
virtual Cell read(Addr addr) const noexcept final {
return *reinterpret_cast<const Cell *>(dict + addr);
}
/** Writes the given value to the cell at the given address. */
virtual void write(Addr addr, Cell value) noexcept final {
*reinterpret_cast<Cell *>(dict + addr) = value;
}
/** Returns the value of the byte at the given address. */
virtual uint8_t readbyte(Addr addr) const noexcept final {
return dict[addr];
}
/** Writes the given value to the byte at the given address. */
virtual void writebyte(Addr addr, uint8_t value) noexcept final {
dict[addr] = value;
}
/** Returns the size of the dictionary's memory block. */
virtual unsigned long int capacity() const noexcept final {
return sizeof(dict);
}

@ -1,20 +0,0 @@
# msp430 implementation
This is the MSP430 port of Alee Forth. It produces a binary that enters a REPL made available on the UART peripheral at 115200 baud. The specific target is MSP430G2553.
## Building
1. `make clean` (just in case)
2. `make msp430-prep`: Builds `alee` for the host computer and uses it to create an `alee.dat` blob containing bytecode for `forth/core.fth` and `forth/msp430.fth`.
3. `make msp430`: Produces `alee-msp430`, a standalone binary for the MSP430 with built-in core and msp430 word-sets.
The final binary is < 11 kB and provides 150 bytes for user dictionary in RAM (assuming 512 bytes of total RAM).
## msp430.fth
The msp430 word-set makes programming for the MSP430 easier:
* All register names are defined (P1OUT, ADC10MEM, etc.).
* `r!` and `r@` to write and read device memory (i.e. registers).
* `rset`, `rclr`, `rtgl` work like `r!` but set, clear, or toggle the given value/mask instead.

@ -16,73 +16,49 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "libalee/alee.hpp"
#include "lzss.h"
static const
#include "msp430fr2476_all.h"
#include "alee.hpp"
#include "libalee/ctype.hpp"
#include "splitmemdict.hpp"
#include <msp430.h>
#include "splitmemdictrw.hpp"
#include "core.fth.h"
static char strbuf[80];
static char strbuf[32];
static void readchar(State& state);
static void serput(int c);
static void serputs(const char *s);
static void printint(DoubleCell n, char *buf, int base);
static Error findword(State&, Word);
static void initGPIO();
static void initClock();
static void initUART();
static void Software_Trim();
#define MCLK_FREQ_MHZ (16)
static void alee_main();
#define ALEE_RODICTSIZE (9088)
__attribute__((section(".lodict")))
#include "core.fth.h"
static bool exitLpm;
static Addr isr_list[24] = {};
using DictType = SplitMemDictRW<ALEE_RODICTSIZE, 32767>;
extern char __dict[sizeof(DictType)];
static auto& dict = *(new (__dict) DictType (alee_dat, 0x10000));
static void printint(DoubleCell n, char *buf);
int main()
{
WDTCTL = WDTPW | WDTHOLD;
DCOCTL = 0;
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
extern char __libaleebegin;
extern char __libaleeend;
extern char __libaleedst;
std::copy(&__libaleebegin, &__libaleeend, &__libaleedst);
P1SEL |= BIT1 | BIT2;
P1SEL2 |= BIT1 | BIT2;
initGPIO();
initClock();
initUART();
SYSCFG0 = FRWPPW;
UCA0CTL1 = UCSWRST;
UCA0CTL1 |= UCSSEL_2;
UCA0BR0 = 104;
UCA0BR1 = 0;
UCA0MCTL = UCBRS0;
UCA0CTL1 &= (uint8_t)~UCSWRST;
alee_main();
}
__enable_interrupt();
LIBALEE_SECTION
void alee_main()
{
(void)alee_dat_len;
static SplitMemDict<alee_dat_len> dict (alee_dat);
State state (dict, readchar);
Parser::customParse = findword;
serputs("alee forth\n\r");
auto ptr = strbuf;
while (1) {
if (UCA0IFG & UCRXIFG) {
auto c = static_cast<char>(UCA0RXBUF);
if (IFG2 & UCA0RXIFG) {
char c = UCA0RXBUF;
serput(c);
if (c == '\r') {
@ -118,38 +94,32 @@ void alee_main()
}
}
LIBALEE_SECTION
void readchar(State& state)
static void readchar(State& state)
{
auto idx = state.dict.read(Dictionary::Input);
Addr addr = Dictionary::Input + sizeof(Cell) + idx;
while (!(UCA0IFG & UCRXIFG));
auto c = static_cast<uint8_t>(UCA0RXBUF);
while (!(IFG2 & UCA0RXIFG));
auto c = UCA0RXBUF;
if (isupper(c))
c += 32;
state.dict.writebyte(addr, c ? c : ' ');
}
LIBALEE_SECTION
void serput(int c)
{
while (!(UCA0IFG & UCTXIFG));
UCA0TXBUF = static_cast<char>(c);
while (!(IFG2 & UCA0TXIFG));
UCA0TXBUF = (char)c;
}
LIBALEE_SECTION
void serputs(const char *s)
{
while (*s)
serput(*s++);
}
LIBALEE_SECTION
void printint(DoubleCell n, char *buf, int base)
void printint(DoubleCell n, char *buf)
{
static const char digit[] = "0123456789ABCDEF";
char *ptr = buf;
bool neg = n < 0;
@ -157,8 +127,8 @@ void printint(DoubleCell n, char *buf, int base)
n = -n;
do {
*ptr++ = digit[n % base];
} while ((n /= base));
*ptr++ = (char)(n % 10) + '0';
} while ((n /= 10));
if (neg)
serput('-');
@ -169,285 +139,30 @@ void printint(DoubleCell n, char *buf, int base)
serput(' ');
}
LIBALEE_SECTION
void user_sys(State& state)
{
switch (state.pop()) {
case 0: // .
printint(state.pop(), strbuf, state.dict.read(Dictionary::Base));
case 0:
printint(state.pop(), strbuf);
break;
case 1: // unused
state.push(static_cast<Addr>(state.dict.capacity() - state.dict.here()));
case 1:
printint(static_cast<Addr>(state.pop()), strbuf);
break;
case 2: // emit
case 2:
serput(state.pop());
break;
case 10:
{ auto index = state.pop() - 20;
isr_list[index] = state.pop(); }
break;
case 11:
case 3:
{ auto addr = state.pop();
*reinterpret_cast<uint8_t *>(addr) = state.pop() & 0xFFu; }
break;
case 12:
case 4:
state.push(*reinterpret_cast<uint8_t *>(state.pop()));
break;
case 13:
{ auto addr = state.pop();
*reinterpret_cast<uint16_t *>(addr) = state.pop() & 0xFFFFu; }
break;
case 14:
state.push(*reinterpret_cast<uint16_t *>(state.pop()));
break;
case 15:
_bis_SR_register(state.pop());
break;
case 16:
_bic_SR_register(state.pop());
break;
case 17:
exitLpm |= true;
break;
case 50:
Parser::customParse = nullptr;
extern char _etext;
state.push((Addr)&_etext);
break;
default:
break;
}
}
#define LZSS_MAGIC_SEPARATOR (0xFB)
static uint8_t lzword[32];
static int lzwlen;
static uint8_t lzbuf[32];
static uint8_t *lzptr;
Error findword(State& state, Word word)
{
uint8_t *ptr = lzword;
for (auto it = word.begin(&state.dict); it != word.end(&state.dict); ++it) {
*ptr = *it;
if (islower(*ptr))
*ptr -= 32;
++ptr;
}
lzwlen = (int)(ptr - lzword);
lzptr = lzbuf;
lzssinit(msp430fr2476_all_lzss, msp430fr2476_all_lzss_len);
auto ret = decode([](int c) {
if (c != LZSS_MAGIC_SEPARATOR) {
*lzptr++ = (uint8_t)c;
} else {
if (lzwlen == lzptr - lzbuf - 2 && std::equal(lzbuf, lzptr - 2, lzword)) {
lzwlen = (*(lzptr - 2) << 8) | *(lzptr - 1);
return 1;
} else {
lzptr = lzbuf;
}
}
return 0;
});
if (ret == EOF) {
return Error::noword;
} else {
Parser::processLiteral(state, (Cell)lzwlen);
return Error::none;
}
}
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
}
bool alee_isr_handle(unsigned index)
{
const Addr isr = isr_list[index];
if (isr != 0) {
State isrstate (dict, readchar);
exitLpm = false;
isrstate.execute(isr);
return exitLpm;
}
return false;
}
#define DEFINE_ISR(VVV, III) \
__attribute__((interrupt(VVV))) \
void VVV##_ISR() { \
if (alee_isr_handle(III)) \
_low_power_mode_off_on_exit(); }
DEFINE_ISR(ECOMP0_VECTOR, 0)
DEFINE_ISR(PORT6_VECTOR, 1)
DEFINE_ISR(PORT5_VECTOR, 2)
DEFINE_ISR(PORT4_VECTOR, 3)
DEFINE_ISR(PORT3_VECTOR, 4)
DEFINE_ISR(PORT2_VECTOR, 5)
DEFINE_ISR(PORT1_VECTOR, 6)
DEFINE_ISR(ADC_VECTOR, 7)
DEFINE_ISR(EUSCI_B1_VECTOR, 8)
DEFINE_ISR(EUSCI_B0_VECTOR, 9)
DEFINE_ISR(EUSCI_A1_VECTOR, 10)
DEFINE_ISR(EUSCI_A0_VECTOR, 11)
DEFINE_ISR(WDT_VECTOR, 12)
DEFINE_ISR(RTC_VECTOR, 13)
DEFINE_ISR(TIMER0_B1_VECTOR, 14)
DEFINE_ISR(TIMER0_B0_VECTOR, 15)
DEFINE_ISR(TIMER3_A1_VECTOR, 16)
DEFINE_ISR(TIMER3_A0_VECTOR, 17)
DEFINE_ISR(TIMER2_A1_VECTOR, 18)
DEFINE_ISR(TIMER2_A0_VECTOR, 19)
DEFINE_ISR(TIMER1_A1_VECTOR, 20)
DEFINE_ISR(TIMER1_A0_VECTOR, 21)
DEFINE_ISR(TIMER0_A1_VECTOR, 22)
DEFINE_ISR(TIMER0_A0_VECTOR, 23)
// Override newlib's free to save hundreds of bytes
extern "C" void free(void *) {}
extern "C" int atexit(void (*)()) { return 0; }
void operator delete(void *) {}
void operator delete(void *, std::size_t) {}

@ -1,9 +0,0 @@
#!/bin/bash -x
cat msp430fr2476_symbols.ld | grep "^PROVIDE.*" | sed -e "s/^PROVIDE(//" -e "s/[ ][ ]*//" -e "s/=.0x/\\\\x/" -e "s/..);/\\\\x&/" -e "s/);//" > msp430fr2476_symbols.dat
grep -E "^#define \w+\s+\([0-9].*$" msp430fr2476.h | sed -e "s/).*$/)/" -e "s/^#define //" -e "s/[ ][ ]*//" -e "s/(0x/\\\\x/" -e "s/..)/\\\\x&/" -e "s/)//" -e "s/(/\\\\x/" -e "s/\\\\x\\\\/\\\\x00\\\\/" > msp430fr2476.dat
cat msp430fr2476_symbols.dat msp430fr2476.dat | tr '\n' '\373' | tr -d '\r' > msp430fr2476_all.dat
echo -e "$(cat msp430fr2476_all.dat)" > msp430fr2476_all.bin
./lzss e msp430fr2476_all.bin msp430fr2476_all.lzss
ls -l msp430fr2476_all.lzss
xxd -i msp430fr2476_all.lzss > msp430fr2476_all.h

@ -1,15 +0,0 @@
unsigned char RXData = 0;
unsigned char TXData;
: spi-init
bit2 bit5 or bit6 or p3sel0 byte set
ucb1ctlw0
ucswrst over reg set
ucmst ucsync or ucckpl or ucmsb or over reg set
ucssel__aclk over reg set
2 ucb1brw reg!
ucswrst swap reg clear ;
: spi-emit
begin ucb1ifg reg@ uctxifg and until
ucb1txbuf reg! ;

@ -1,13 +0,0 @@
\ UART example, 19200 baud, pins D0/1
: uart-init ( -- )
bit5 bit6 or p2sel0 byte set
ucswrst uca1ctlw0 reg set
ucssel__smclk uca1ctlw0 reg set
52 uca1brw reg!
18688 ucos16 or ucbrf0 or uca1mctlw reg!
ucswrst uca1ctlw0 reg clear ;
: uart-emit ( n -- )
begin uca1ifg reg@ uctxifg and until
uca1txbuf byte! ;

@ -1,181 +0,0 @@
/* LZSS encoder-decoder (Haruhiko Okumura; public domain) */
#include <stdio.h>
#include <stdlib.h>
#define EI 8 /* typically 10..13 */
#define EJ 3 /* typically 4..5 */
#define P 1 /* If match length <= P then output one character */
#define N (1 << EI) /* buffer size */
#define F ((1 << EJ) + 1) /* lookahead buffer size */
int bit_buffer = 0, bit_mask = 128;
unsigned long codecount = 0, textcount = 0;
unsigned char buffer[N * 2];
FILE *infile, *outfile;
void error(void)
{
printf("Output error\n"); exit(1);
}
void putbit1(void)
{
bit_buffer |= bit_mask;
if ((bit_mask >>= 1) == 0) {
if (fputc(bit_buffer, outfile) == EOF) error();
bit_buffer = 0; bit_mask = 128; codecount++;
}
}
void putbit0(void)
{
if ((bit_mask >>= 1) == 0) {
if (fputc(bit_buffer, outfile) == EOF) error();
bit_buffer = 0; bit_mask = 128; codecount++;
}
}
void flush_bit_buffer(void)
{
if (bit_mask != 128) {
if (fputc(bit_buffer, outfile) == EOF) error();
codecount++;
}
}
void output1(int c)
{
int mask;
putbit1();
mask = 256;
while (mask >>= 1) {
if (c & mask) putbit1();
else putbit0();
}
}
void output2(int x, int y)
{
int mask;
putbit0();
mask = N;
while (mask >>= 1) {
if (x & mask) putbit1();
else putbit0();
}
mask = (1 << EJ);
while (mask >>= 1) {
if (y & mask) putbit1();
else putbit0();
}
}
void encode(void)
{
int i, j, f1, x, y, r, s, bufferend, c;
for (i = 0; i < N - F; i++) buffer[i] = ' ';
for (i = N - F; i < N * 2; i++) {
if ((c = fgetc(infile)) == EOF) break;
buffer[i] = c; textcount++;
}
bufferend = i; r = N - F; s = 0;
while (r < bufferend) {
f1 = (F <= bufferend - r) ? F : bufferend - r;
x = 0; y = 1; c = buffer[r];
for (i = r - 1; i >= s; i--)
if (buffer[i] == c) {
for (j = 1; j < f1; j++)
if (buffer[i + j] != buffer[r + j]) break;
if (j > y) {
x = i; y = j;
}
}
if (y <= P) { y = 1; output1(c); }
else output2(x & (N - 1), y - 2);
r += y; s += y;
if (r >= N * 2 - F) {
for (i = 0; i < N; i++) buffer[i] = buffer[i + N];
bufferend -= N; r -= N; s -= N;
while (bufferend < N * 2) {
if ((c = fgetc(infile)) == EOF) break;
buffer[bufferend++] = c; textcount++;
}
}
}
flush_bit_buffer();
printf("text: %ld bytes\n", textcount);
printf("code: %ld bytes (%ld%%)\n",
codecount, (codecount * 100) / textcount);
}
int getbit(int n) /* get n bits */
{
int i, x;
static int buf, mask = 0;
x = 0;
for (i = 0; i < n; i++) {
if (mask == 0) {
if ((buf = fgetc(infile)) == EOF) return EOF;
mask = 128;
}
x <<= 1;
if (buf & mask) x++;
mask >>= 1;
}
return x;
}
void decode(void)
{
int i, j, k, r, c;
for (i = 0; i < N - F; i++) buffer[i] = ' ';
r = N - F;
while ((c = getbit(1)) != EOF) {
if (c) {
if ((c = getbit(8)) == EOF) break;
fputc(c, outfile);
buffer[r++] = c; r &= (N - 1);
} else {
if ((i = getbit(EI)) == EOF) break;
if ((j = getbit(EJ)) == EOF) break;
for (k = 0; k <= j + 1; k++) {
c = buffer[(i + k) & (N - 1)];
fputc(c, outfile);
buffer[r++] = c; r &= (N - 1);
}
}
}
}
int main(int argc, char *argv[])
{
int enc;
char *s;
if (argc != 4) {
printf("Usage: lzss e/d infile outfile\n\te = encode\td = decode\n");
return 1;
}
s = argv[1];
if (s[1] == 0 && (*s == 'd' || *s == 'D' || *s == 'e' || *s == 'E'))
enc = (*s == 'e' || *s == 'E');
else {
printf("? %s\n", s); return 1;
}
if ((infile = fopen(argv[2], "rb")) == NULL) {
printf("? %s\n", argv[2]); return 1;
}
if ((outfile = fopen(argv[3], "wb")) == NULL) {
printf("? %s\n", argv[3]); return 1;
}
if (enc) encode(); else decode();
fclose(infile); fclose(outfile);
return 0;
}

@ -1,74 +0,0 @@
/* LZSS encoder-decoder (Haruhiko Okumura; public domain) */
/* Modified by Clyne Sullivan to focus on streamed decompression. */
#ifndef EOF
#define EOF (-1)
#endif
#define EI 8 /* typically 10..13 */
#define EJ 3 /* typically 4..5 */
#define N (1 << EI) /* buffer size */
#define F ((1 << EJ) + 1) /* lookahead buffer size */
static unsigned char buffer[N * 2];
static const unsigned char *inbuffer;
static unsigned int insize, inidx;
static int buf, mask;
/* Prepares decode() to decompress the given data. */
void lzssinit(const unsigned char *inb, unsigned int ins)
{
inbuffer = inb;
insize = ins;
inidx = 0;
buf = 0;
mask = 0;
}
int getbit(int n) /* get n bits */
{
int i, x;
x = 0;
for (i = 0; i < n; i++) {
if (mask == 0) {
if (inidx >= insize)
return EOF;
buf = inbuffer[inidx++];
mask = 128;
}
x <<= 1;
if (buf & mask) x++;
mask >>= 1;
}
return x;
}
/* handleoutput() receives each decompressed byte, return zero if want more. */
int decode(int (*handleoutput)(int))
{
int i, j, k, r, c, ret;
for (i = 0; i < N - F; i++) buffer[i] = ' ';
r = N - F;
while ((c = getbit(1)) != EOF) {
if (c) {
if ((c = getbit(8)) == EOF) break;
if ((ret = handleoutput(c)))
return ret;
buffer[r++] =(unsigned char) c; r &= (N - 1);
} else {
if ((i = getbit(EI)) == EOF) break;
if ((j = getbit(EJ)) == EOF) break;
for (k = 0; k <= j + 1; k++) {
c = buffer[(i + k) & (N - 1)];
if ((ret = handleoutput(c)))
return ret;
buffer[r++] = (unsigned char)c; r &= (N - 1);
}
}
}
return EOF;
}

File diff suppressed because it is too large Load Diff

@ -1,376 +0,0 @@
/* ============================================================================ */
/* Copyright (c) 2021, Texas Instruments Incorporated */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions */
/* are met: */
/* */
/* * Redistributions of source code must retain the above copyright */
/* notice, this list of conditions and the following disclaimer. */
/* */
/* * Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in the */
/* documentation and/or other materials provided with the distribution. */
/* */
/* * Neither the name of Texas Instruments Incorporated nor the names of */
/* its contributors may be used to endorse or promote products derived */
/* from this software without specific prior written permission. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" */
/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, */
/* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR */
/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, */
/* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, */
/* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; */
/* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */
/* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR */
/* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/* ============================================================================ */
/* This file supports MSP430FR2476 devices. */
/* Version: 1.212 */
/* Default linker script, for normal executables */
OUTPUT_ARCH(msp430)
ENTRY(_start)
MEMORY {
TINYRAM : ORIGIN = 0x0006, LENGTH = 0x001A /* END=0x001F, size 26 */
BSL0 : ORIGIN = 0x1000, LENGTH = 0x0800 /* END=0x17FF, size 2048 */
TLVMEM : ORIGIN = 0x1A00, LENGTH = 0x0200 /* END=0x1BFF, size 512 */
BOOTCODE : ORIGIN = 0x1C00, LENGTH = 0x0400 /* END=0x1FFF, size 1024 */
ROMLIB : ORIGIN = 0xC0000, LENGTH = 0x4000 /* END=0xC3FFF, size 16384 */
BSL1 : ORIGIN = 0xFFC00, LENGTH = 0x0400 /* END=0xFFFFF, size 1024 */
RAM (rwx) : ORIGIN = 0x2000, LENGTH = 0x2000 /* END=0x3FFF, size 8192 */
INFOMEM : ORIGIN = 0x1800, LENGTH = 0x0200 /* END=0x19FF, size 512 */
FRAM (rwx) : ORIGIN = 0x8000, LENGTH = 0x7F80 /* END=0xFF7F, size 32640 */
HIFRAM (rxw) : ORIGIN = 0x10000, LENGTH = 0x00007FFF
JTAGSIGNATURE : ORIGIN = 0xFF80, LENGTH = 0x0004
BSLSIGNATURE : ORIGIN = 0xFF84, LENGTH = 0x0004
BSLCONFIGURATIONSIGNATURE : ORIGIN = 0xFF88, LENGTH = 0x0002
BSLCONFIGURATION : ORIGIN = 0xFF8A, LENGTH = 0x0002
BSLI2CADDRESS : ORIGIN = 0xFFA0, LENGTH = 0x0002
VECT0 : ORIGIN = 0xFFA2, LENGTH = 0x0002
VECT1 : ORIGIN = 0xFFA4, LENGTH = 0x0002
VECT2 : ORIGIN = 0xFFA6, LENGTH = 0x0002
VECT3 : ORIGIN = 0xFFA8, LENGTH = 0x0002
VECT4 : ORIGIN = 0xFFAA, LENGTH = 0x0002
VECT5 : ORIGIN = 0xFFAC, LENGTH = 0x0002
VECT6 : ORIGIN = 0xFFAE, LENGTH = 0x0002
VECT7 : ORIGIN = 0xFFB0, LENGTH = 0x0002
VECT8 : ORIGIN = 0xFFB2, LENGTH = 0x0002
VECT9 : ORIGIN = 0xFFB4, LENGTH = 0x0002
VECT10 : ORIGIN = 0xFFB6, LENGTH = 0x0002
VECT11 : ORIGIN = 0xFFB8, LENGTH = 0x0002
VECT12 : ORIGIN = 0xFFBA, LENGTH = 0x0002
VECT13 : ORIGIN = 0xFFBC, LENGTH = 0x0002
VECT14 : ORIGIN = 0xFFBE, LENGTH = 0x0002
VECT15 : ORIGIN = 0xFFC0, LENGTH = 0x0002
VECT16 : ORIGIN = 0xFFC2, LENGTH = 0x0002
VECT17 : ORIGIN = 0xFFC4, LENGTH = 0x0002
VECT18 : ORIGIN = 0xFFC6, LENGTH = 0x0002
VECT19 : ORIGIN = 0xFFC8, LENGTH = 0x0002
VECT20 : ORIGIN = 0xFFCA, LENGTH = 0x0002
VECT21 : ORIGIN = 0xFFCC, LENGTH = 0x0002
VECT22 : ORIGIN = 0xFFCE, LENGTH = 0x0002
VECT23 : ORIGIN = 0xFFD0, LENGTH = 0x0002
VECT24 : ORIGIN = 0xFFD2, LENGTH = 0x0002
VECT25 : ORIGIN = 0xFFD4, LENGTH = 0x0002
VECT26 : ORIGIN = 0xFFD6, LENGTH = 0x0002
VECT27 : ORIGIN = 0xFFD8, LENGTH = 0x0002
VECT28 : ORIGIN = 0xFFDA, LENGTH = 0x0002
VECT29 : ORIGIN = 0xFFDC, LENGTH = 0x0002
VECT30 : ORIGIN = 0xFFDE, LENGTH = 0x0002
VECT31 : ORIGIN = 0xFFE0, LENGTH = 0x0002
VECT32 : ORIGIN = 0xFFE2, LENGTH = 0x0002
VECT33 : ORIGIN = 0xFFE4, LENGTH = 0x0002
VECT34 : ORIGIN = 0xFFE6, LENGTH = 0x0002
VECT35 : ORIGIN = 0xFFE8, LENGTH = 0x0002
VECT36 : ORIGIN = 0xFFEA, LENGTH = 0x0002
VECT37 : ORIGIN = 0xFFEC, LENGTH = 0x0002
VECT38 : ORIGIN = 0xFFEE, LENGTH = 0x0002
VECT39 : ORIGIN = 0xFFF0, LENGTH = 0x0002
VECT40 : ORIGIN = 0xFFF2, LENGTH = 0x0002
VECT41 : ORIGIN = 0xFFF4, LENGTH = 0x0002
VECT42 : ORIGIN = 0xFFF6, LENGTH = 0x0002
VECT43 : ORIGIN = 0xFFF8, LENGTH = 0x0002
VECT44 : ORIGIN = 0xFFFA, LENGTH = 0x0002
VECT45 : ORIGIN = 0xFFFC, LENGTH = 0x0002
RESETVEC : ORIGIN = 0xFFFE, LENGTH = 0x0002
}
SECTIONS
{
.jtagsignature : {} > JTAGSIGNATURE
.bslsignature : {} > BSLSIGNATURE
.bslconfigsignature : {} > BSLCONFIGURATIONSIGNATURE
.bslconfig : {} > BSLCONFIGURATION
.bsli2caddress : {} > BSLI2CADDRESS
__interrupt_vector_0 : { KEEP (*(__interrupt_vector_0 )) } > VECT0
__interrupt_vector_1 : { KEEP (*(__interrupt_vector_1 )) } > VECT1
__interrupt_vector_2 : { KEEP (*(__interrupt_vector_2 )) } > VECT2
__interrupt_vector_3 : { KEEP (*(__interrupt_vector_3 )) } > VECT3
__interrupt_vector_4 : { KEEP (*(__interrupt_vector_4 )) } > VECT4
__interrupt_vector_5 : { KEEP (*(__interrupt_vector_5 )) } > VECT5
__interrupt_vector_6 : { KEEP (*(__interrupt_vector_6 )) } > VECT6
__interrupt_vector_7 : { KEEP (*(__interrupt_vector_7 )) } > VECT7
__interrupt_vector_8 : { KEEP (*(__interrupt_vector_8 )) } > VECT8
__interrupt_vector_9 : { KEEP (*(__interrupt_vector_9 )) } > VECT9
__interrupt_vector_10 : { KEEP (*(__interrupt_vector_10)) } > VECT10
__interrupt_vector_11 : { KEEP (*(__interrupt_vector_11)) } > VECT11
__interrupt_vector_12 : { KEEP (*(__interrupt_vector_12)) } > VECT12
__interrupt_vector_13 : { KEEP (*(__interrupt_vector_13)) } > VECT13
__interrupt_vector_14 : { KEEP (*(__interrupt_vector_14)) } > VECT14
__interrupt_vector_15 : { KEEP (*(__interrupt_vector_15)) } > VECT15
__interrupt_vector_16 : { KEEP (*(__interrupt_vector_16)) } > VECT16
__interrupt_vector_17 : { KEEP (*(__interrupt_vector_17)) } > VECT17
__interrupt_vector_18 : { KEEP (*(__interrupt_vector_18)) } > VECT18
__interrupt_vector_19 : { KEEP (*(__interrupt_vector_19)) } > VECT19
__interrupt_vector_20 : { KEEP (*(__interrupt_vector_20)) KEEP (*(__interrupt_vector_ecomp0)) } > VECT20
__interrupt_vector_21 : { KEEP (*(__interrupt_vector_21)) KEEP (*(__interrupt_vector_port6)) } > VECT21
__interrupt_vector_22 : { KEEP (*(__interrupt_vector_22)) KEEP (*(__interrupt_vector_port5)) } > VECT22
__interrupt_vector_23 : { KEEP (*(__interrupt_vector_23)) KEEP (*(__interrupt_vector_port4)) } > VECT23
__interrupt_vector_24 : { KEEP (*(__interrupt_vector_24)) KEEP (*(__interrupt_vector_port3)) } > VECT24
__interrupt_vector_25 : { KEEP (*(__interrupt_vector_25)) KEEP (*(__interrupt_vector_port2)) } > VECT25
__interrupt_vector_26 : { KEEP (*(__interrupt_vector_26)) KEEP (*(__interrupt_vector_port1)) } > VECT26
__interrupt_vector_27 : { KEEP (*(__interrupt_vector_27)) KEEP (*(__interrupt_vector_adc)) } > VECT27
__interrupt_vector_28 : { KEEP (*(__interrupt_vector_28)) KEEP (*(__interrupt_vector_eusci_b1)) } > VECT28
__interrupt_vector_29 : { KEEP (*(__interrupt_vector_29)) KEEP (*(__interrupt_vector_eusci_b0)) } > VECT29
__interrupt_vector_30 : { KEEP (*(__interrupt_vector_30)) KEEP (*(__interrupt_vector_eusci_a1)) } > VECT30
__interrupt_vector_31 : { KEEP (*(__interrupt_vector_31)) KEEP (*(__interrupt_vector_eusci_a0)) } > VECT31
__interrupt_vector_32 : { KEEP (*(__interrupt_vector_32)) KEEP (*(__interrupt_vector_wdt)) } > VECT32
__interrupt_vector_33 : { KEEP (*(__interrupt_vector_33)) KEEP (*(__interrupt_vector_rtc)) } > VECT33
__interrupt_vector_34 : { KEEP (*(__interrupt_vector_34)) KEEP (*(__interrupt_vector_timer0_b1)) } > VECT34
__interrupt_vector_35 : { KEEP (*(__interrupt_vector_35)) KEEP (*(__interrupt_vector_timer0_b0)) } > VECT35
__interrupt_vector_36 : { KEEP (*(__interrupt_vector_36)) KEEP (*(__interrupt_vector_timer3_a1)) } > VECT36
__interrupt_vector_37 : { KEEP (*(__interrupt_vector_37)) KEEP (*(__interrupt_vector_timer3_a0)) } > VECT37
__interrupt_vector_38 : { KEEP (*(__interrupt_vector_38)) KEEP (*(__interrupt_vector_timer2_a1)) } > VECT38
__interrupt_vector_39 : { KEEP (*(__interrupt_vector_39)) KEEP (*(__interrupt_vector_timer2_a0)) } > VECT39
__interrupt_vector_40 : { KEEP (*(__interrupt_vector_40)) KEEP (*(__interrupt_vector_timer1_a1)) } > VECT40
__interrupt_vector_41 : { KEEP (*(__interrupt_vector_41)) KEEP (*(__interrupt_vector_timer1_a0)) } > VECT41
__interrupt_vector_42 : { KEEP (*(__interrupt_vector_42)) KEEP (*(__interrupt_vector_timer0_a1)) } > VECT42
__interrupt_vector_43 : { KEEP (*(__interrupt_vector_43)) KEEP (*(__interrupt_vector_timer0_a0)) } > VECT43
__interrupt_vector_44 : { KEEP (*(__interrupt_vector_44)) KEEP (*(__interrupt_vector_unmi)) } > VECT44
__interrupt_vector_45 : { KEEP (*(__interrupt_vector_45)) KEEP (*(__interrupt_vector_sysnmi)) } > VECT45
__reset_vector :
{
KEEP (*(__interrupt_vector_46))
KEEP (*(__interrupt_vector_reset))
KEEP (*(.resetvec))
} > RESETVEC
.rodata :
{
. = ALIGN(2);
*(.rodata .rodata.* .gnu.linkonce.r.* .const .const:*)
*(.rodata1)
} > FRAM
/* Note: This is a separate .rodata section for sections which are
read only but which older linkers treat as read-write.
This prevents older linkers from marking the entire .rodata
section as read-write. */
.rodata2 :
{
. = ALIGN(2);
PROVIDE (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE (__preinit_array_end = .);
. = ALIGN(2);
PROVIDE (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE (__init_array_end = .);
. = ALIGN(2);
PROVIDE (__fini_array_start = .);
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
PROVIDE (__fini_array_end = .);
. = ALIGN(2);
/* gcc uses crtbegin.o to find the start of the constructors, so
we make sure it is first. Because this is a wildcard, it
doesn't matter if the user does not actually link against
crtbegin.o; the linker won't look for a file to match a
wildcard. The wildcard also means that it doesn't matter which
directory crtbegin.o is in. */
KEEP (*crtbegin*.o(.ctors))
/* We don't want to include the .ctor section from the crtend.o
file until after the sorted ctors. The .ctor section from
the crtend file contains the end of ctors marker and it must
be last */
KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
KEEP (*crtbegin*.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} > FRAM
.tinyram : {
PROVIDE (__dict = .);
} > TINYRAM
.libalee : {
. = ALIGN(2);
PROVIDE (__libaleedst = .);
*(.libalee)
} > RAM AT> FRAM
PROVIDE(__libaleebegin = LOADADDR(.libalee));
PROVIDE (__libaleeend = LOADADDR(.libalee) + SIZEOF(.libalee));
.data :
{
. = ALIGN(2);
PROVIDE (__datastart = .);
*(.data .data.* .gnu.linkonce.d.*)
KEEP (*(.gnu.linkonce.d.*personality*))
SORT(CONSTRUCTORS)
*(.data1)
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
. = ALIGN(2);
*(.sdata .sdata.* .gnu.linkonce.s.* D_2 D_1)
. = ALIGN(2);
_edata = .;
PROVIDE (edata = .);
PROVIDE (__dataend = .);
} > RAM AT> FRAM
/* Note that crt0 assumes this is a multiple of two; all the
start/stop symbols are also assumed word-aligned. */
PROVIDE(__romdatastart = LOADADDR(.data));
PROVIDE (__romdatacopysize = SIZEOF(.data));
.bss :
{
. = ALIGN(2);
PROVIDE (__bssstart = .);
*(.sbss .sbss.*)
*(.bss .bss.* .gnu.linkonce.b.*)
. = ALIGN(2);
*(COMMON)
PROVIDE (__bssend = .);
} > RAM
PROVIDE (__bsssize = SIZEOF(.bss));
/* This section contains data that is not initialised during load
or application reset. */
.noinit (NOLOAD) :
{
. = ALIGN(2);
PROVIDE (__noinit_start = .);
*(.noinit)
. = ALIGN(2);
PROVIDE (__noinit_end = .);
} > RAM
.stack (ORIGIN (RAM) + LENGTH(RAM)) :
{
PROVIDE (__stack = .);
*(.stack)
}
.hidict :
{
. = ALIGN(2);
*(.hidict)
} > HIFRAM
.text :
{
PROVIDE (_start = .);
. = ALIGN(2);
KEEP (*(SORT(.crt_*)))
. = ALIGN(2);
*(.text .stub .text.* .gnu.linkonce.t.* .text:*)
. = ALIGN(2);
KEEP (*(.init))
KEEP (*(.fini))
KEEP (*(.tm_clone_table))
. = ALIGN(2);
PROVIDE (_etext = .);
} > FRAM
.lodict :
{
. = ALIGN(1024);
*(.lodict)
} > FRAM
.info (NOLOAD) : {} > INFOMEM /* MSP430 INFO FLASH MEMORY SEGMENTS */
/* The rest are all not normally part of the runtime image. */
.MSP430.attributes 0 :
{
KEEP (*(.MSP430.attributes))
KEEP (*(.gnu.attributes))
KEEP (*(__TI_build_attributes))
}
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1. */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions. */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2. */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2. */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions. */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
/DISCARD/ : { *(.note.GNU-stack .debug_loclists) }
}
/****************************************************************************/
/* Include peripherals memory map */
/****************************************************************************/
INCLUDE msp430fr2476_symbols.ld

File diff suppressed because it is too large Load Diff

@ -0,0 +1,315 @@
/* ============================================================================ */
/* Copyright (c) 2021, Texas Instruments Incorporated */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions */
/* are met: */
/* */
/* * Redistributions of source code must retain the above copyright */
/* notice, this list of conditions and the following disclaimer. */
/* */
/* * Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in the */
/* documentation and/or other materials provided with the distribution. */
/* */
/* * Neither the name of Texas Instruments Incorporated nor the names of */
/* its contributors may be used to endorse or promote products derived */
/* from this software without specific prior written permission. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" */
/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, */
/* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR */
/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, */
/* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, */
/* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; */
/* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */
/* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR */
/* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/* ============================================================================ */
/* This file supports MSP430G2553 devices. */
/* Version: 1.212 */
/* Default linker script, for normal executables */
OUTPUT_ARCH(msp430)
ENTRY(_start)
MEMORY {
SFR : ORIGIN = 0x0000, LENGTH = 0x0010 /* END=0x0010, size 16 */
RAM : ORIGIN = 0x0200, LENGTH = 0x0200 /* END=0x03FF, size 512 */
INFOMEM : ORIGIN = 0x1000, LENGTH = 0x0100 /* END=0x10FF, size 256 as 4 64-byte segments */
INFOA : ORIGIN = 0x10C0, LENGTH = 0x0040 /* END=0x10FF, size 64 */
INFOB : ORIGIN = 0x1080, LENGTH = 0x0040 /* END=0x10BF, size 64 */
INFOC : ORIGIN = 0x1040, LENGTH = 0x0040 /* END=0x107F, size 64 */
INFOD : ORIGIN = 0x1000, LENGTH = 0x0040 /* END=0x103F, size 64 */
ROM (rx) : ORIGIN = 0xC000, LENGTH = 0x3FDE /* END=0xFFDD, size 16350 */
BSLSIGNATURE : ORIGIN = 0xFFDE, LENGTH = 0x0002
VECT1 : ORIGIN = 0xFFE0, LENGTH = 0x0002
VECT2 : ORIGIN = 0xFFE2, LENGTH = 0x0002
VECT3 : ORIGIN = 0xFFE4, LENGTH = 0x0002
VECT4 : ORIGIN = 0xFFE6, LENGTH = 0x0002
VECT5 : ORIGIN = 0xFFE8, LENGTH = 0x0002
VECT6 : ORIGIN = 0xFFEA, LENGTH = 0x0002
VECT7 : ORIGIN = 0xFFEC, LENGTH = 0x0002
VECT8 : ORIGIN = 0xFFEE, LENGTH = 0x0002
VECT9 : ORIGIN = 0xFFF0, LENGTH = 0x0002
VECT10 : ORIGIN = 0xFFF2, LENGTH = 0x0002
VECT11 : ORIGIN = 0xFFF4, LENGTH = 0x0002
VECT12 : ORIGIN = 0xFFF6, LENGTH = 0x0002
VECT13 : ORIGIN = 0xFFF8, LENGTH = 0x0002
VECT14 : ORIGIN = 0xFFFA, LENGTH = 0x0002
VECT15 : ORIGIN = 0xFFFC, LENGTH = 0x0002
RESETVEC : ORIGIN = 0xFFFE, LENGTH = 0x0002
}
SECTIONS
{
.bslsignature : {} > BSLSIGNATURE
__interrupt_vector_1 : { KEEP (*(__interrupt_vector_1 )) KEEP (*(__interrupt_vector_trapint)) } > VECT1
__interrupt_vector_2 : { KEEP (*(__interrupt_vector_2 )) } > VECT2
__interrupt_vector_3 : { KEEP (*(__interrupt_vector_3 )) KEEP (*(__interrupt_vector_port1)) } > VECT3
__interrupt_vector_4 : { KEEP (*(__interrupt_vector_4 )) KEEP (*(__interrupt_vector_port2)) } > VECT4
__interrupt_vector_5 : { KEEP (*(__interrupt_vector_5 )) } > VECT5
__interrupt_vector_6 : { KEEP (*(__interrupt_vector_6 )) KEEP (*(__interrupt_vector_adc10)) } > VECT6
__interrupt_vector_7 : { KEEP (*(__interrupt_vector_7 )) KEEP (*(__interrupt_vector_usciab0tx)) } > VECT7
__interrupt_vector_8 : { KEEP (*(__interrupt_vector_8 )) KEEP (*(__interrupt_vector_usciab0rx)) } > VECT8
__interrupt_vector_9 : { KEEP (*(__interrupt_vector_9 )) KEEP (*(__interrupt_vector_timer0_a1)) } > VECT9
__interrupt_vector_10 : { KEEP (*(__interrupt_vector_10)) KEEP (*(__interrupt_vector_timer0_a0)) } > VECT10
__interrupt_vector_11 : { KEEP (*(__interrupt_vector_11)) KEEP (*(__interrupt_vector_wdt)) } > VECT11
__interrupt_vector_12 : { KEEP (*(__interrupt_vector_12)) KEEP (*(__interrupt_vector_comparatora)) } > VECT12
__interrupt_vector_13 : { KEEP (*(__interrupt_vector_13)) KEEP (*(__interrupt_vector_timer1_a1)) } > VECT13
__interrupt_vector_14 : { KEEP (*(__interrupt_vector_14)) KEEP (*(__interrupt_vector_timer1_a0)) } > VECT14
__interrupt_vector_15 : { KEEP (*(__interrupt_vector_15)) KEEP (*(__interrupt_vector_nmi)) } > VECT15
__reset_vector :
{
KEEP (*(__interrupt_vector_16))
KEEP (*(__interrupt_vector_reset))
KEEP (*(.resetvec))
} > RESETVEC
.rodata :
{
. = ALIGN(2);
*(.plt)
*(.rodata .rodata.* .gnu.linkonce.r.* .const .const:*)
*(.rodata1)
KEEP (*(.gcc_except_table)) *(.gcc_except_table.*)
} > ROM
/* Note: This is a separate .rodata section for sections which are
read only but which older linkers treat as read-write.
This prevents older linkers from marking the entire .rodata
section as read-write. */
.rodata2 :
{
. = ALIGN(2);
PROVIDE (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE (__preinit_array_end = .);
. = ALIGN(2);
PROVIDE (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE (__init_array_end = .);
. = ALIGN(2);
PROVIDE (__fini_array_start = .);
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
PROVIDE (__fini_array_end = .);
/* . = ALIGN(2);
*(.eh_frame_hdr)
KEEP (*(.eh_frame)) */
/* gcc uses crtbegin.o to find the start of the constructors, so
we make sure it is first. Because this is a wildcard, it
doesn't matter if the user does not actually link against
crtbegin.o; the linker won't look for a file to match a
wildcard. The wildcard also means that it doesn't matter which
directory crtbegin.o is in. */
KEEP (*crtbegin*.o(.ctors))
/* We don't want to include the .ctor section from the crtend.o
file until after the sorted ctors. The .ctor section from
the crtend file contains the end of ctors marker and it must
be last */
KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
KEEP (*crtbegin*.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} > ROM
.text :
{
. = ALIGN(2);
PROVIDE (_start = .);
KEEP (*(SORT(.crt_*)))
*(.lowtext .text .stub .text.* .gnu.linkonce.t.* .text:*)
KEEP (*(.text.*personality*))
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.interp .hash .dynsym .dynstr .gnu.version*)
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(2);
KEEP (*(.init))
KEEP (*(.fini))
KEEP (*(.tm_clone_table))
} > ROM
.data :
{
. = ALIGN(2);
PROVIDE (__datastart = .);
KEEP (*(.jcr))
*(.data.rel.ro.local) *(.data.rel.ro*)
*(.dynamic)
*(.data .data.* .gnu.linkonce.d.*)
KEEP (*(.gnu.linkonce.d.*personality*))
SORT(CONSTRUCTORS)
*(.data1)
*(.got.plt) *(.got)
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
. = ALIGN(2);
*(.sdata .sdata.* .gnu.linkonce.s.* D_2 D_1)
. = ALIGN(2);
_edata = .;
PROVIDE (edata = .);
PROVIDE (__dataend = .);
} > RAM AT>ROM
/* Note that crt0 assumes this is a multiple of two; all the
start/stop symbols are also assumed word-aligned. */
PROVIDE(__romdatastart = LOADADDR(.data));
PROVIDE (__romdatacopysize = SIZEOF(.data));
.bss :
{
. = ALIGN(2);
PROVIDE (__bssstart = .);
*(.dynbss)
*(.sbss .sbss.*)
*(.bss .bss.* .gnu.linkonce.b.*)
. = ALIGN(2);
*(COMMON)
PROVIDE (__bssend = .);
} > RAM
PROVIDE (__bsssize = SIZEOF(.bss));
/* This section contains data that is not initialised during load
or application reset. */
.noinit (NOLOAD) :
{
. = ALIGN(2);
PROVIDE (__noinit_start = .);
*(.noinit)
. = ALIGN(2);
PROVIDE (__noinit_end = .);
end = .;
} > RAM
/* We create this section so that "end" will always be in the
RAM region (matching .stack below), even if the .bss
section is empty. */
.heap (NOLOAD) :
{
. = ALIGN(2);
__heap_start__ = .;
_end = __heap_start__;
PROVIDE (end = .);
KEEP (*(.heap))
_end = .;
PROVIDE (end = .);
/* This word is here so that the section is not empty, and thus
not discarded by the linker. The actual value does not matter
and is ignored. */
LONG(0);
__heap_end__ = .;
__HeapLimit = __heap_end__;
} > RAM
/* WARNING: Do not place anything in RAM here.
The heap section must be the last section in RAM and the stack
section must be placed at the very end of the RAM region. */
.stack (ORIGIN (RAM) + LENGTH(RAM)) :
{
PROVIDE (__stack = .);
*(.stack)
}
.infoA : {} > INFOA /* MSP430 INFO FLASH MEMORY SEGMENTS */
.infoB : {} > INFOB
.infoC : {} > INFOC
.infoD : {} > INFOD
/* The rest are all not normally part of the runtime image. */
.MSP430.attributes 0 :
{
KEEP (*(.MSP430.attributes))
KEEP (*(.gnu.attributes))
KEEP (*(__TI_build_attributes))
}
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1. */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions. */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2. */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2. */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions. */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
/DISCARD/ : { *(.note.GNU-stack) }
}
/****************************************************************************/
/* Include peripherals memory map */
/****************************************************************************/
INCLUDE msp430g2553_symbols.ld

@ -19,7 +19,7 @@
#ifndef ALEEFORTH_SPLITMEMDICT_HPP
#define ALEEFORTH_SPLITMEMDICT_HPP
#include "libalee/alee.hpp"
#include "alee.hpp"
#include <algorithm>
@ -35,7 +35,6 @@ class SplitMemDict : public Dictionary
uint8_t rwdict[MemDictSize - Dictionary::Begin] = {0};
uint8_t extra[Dictionary::Begin];
LIBALEE_SECTION
Addr convertAddress(Addr addr) const noexcept {
return addr < RON ? addr : static_cast<Addr>(addr - RON);
}
@ -54,7 +53,6 @@ public:
return *this;
}
LIBALEE_SECTION
virtual Cell read(Addr addr) const noexcept final {
const uint8_t *dict;
if (addr < RON)
@ -65,7 +63,6 @@ public:
return *reinterpret_cast<const Cell *>(dict + convertAddress(addr));
}
LIBALEE_SECTION
virtual void write(Addr addr, Cell value) noexcept final {
if (addr >= RON)
*reinterpret_cast<Cell *>(rwdict + addr - RON) = value;
@ -73,7 +70,6 @@ public:
*reinterpret_cast<Cell *>(extra + addr) = value;
}
LIBALEE_SECTION
virtual uint8_t readbyte(Addr addr) const noexcept final {
const uint8_t *dict;
if (addr < RON)
@ -84,7 +80,6 @@ public:
return dict[convertAddress(addr)];
}
LIBALEE_SECTION
virtual void writebyte(Addr addr, uint8_t value) noexcept final {
if (addr >= RON)
rwdict[addr - RON] = value;
@ -92,7 +87,6 @@ public:
extra[addr] = value;
}
LIBALEE_SECTION
virtual unsigned long int capacity() const noexcept final {
return RON + sizeof(extra) + sizeof(rwdict);
}

@ -1,80 +0,0 @@
/**
* Alee Forth: A portable and concise Forth implementation in modern C++.
* Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ALEEFORTH_SPLITMEMDICTRW_HPP
#define ALEEFORTH_SPLITMEMDICTRW_HPP
#include "libalee/alee.hpp"
#include <algorithm>
template<unsigned long int LON, unsigned long int HIN>
class SplitMemDictRW : public Dictionary
{
uint8_t *lodict;
uint32_t hidict;
public:
constexpr explicit SplitMemDictRW(uint8_t *lo, uint32_t hi):
lodict(lo), hidict(hi) {}
constexpr SplitMemDictRW(const SplitMemDictRW<LON, HIN>& spd):
SplitMemDictRW(spd.lodict, spd.hidict) {}
constexpr auto& operator=(const SplitMemDictRW<LON, HIN>& spd) {
*this = SplitMemDictRW(spd.lodict, hidict);
return *this;
}
virtual Cell read(Addr addr) const noexcept final {
if (addr < LON)
return *reinterpret_cast<const Cell *>(lodict + addr);
else
return _data20_read_short(hidict + addr - LON);
}
virtual void write(Addr addr, Cell value) noexcept final {
if (addr < LON)
*reinterpret_cast<Cell *>(lodict + addr) = value;
else
_data20_write_short(hidict + addr - LON, value);
}
virtual uint8_t readbyte(Addr addr) const noexcept final {
if (addr < LON)
return lodict[addr];
else
return _data20_read_char(hidict + addr - LON);
}
virtual void writebyte(Addr addr, uint8_t value) noexcept final {
if (addr < LON)
lodict[addr] = value;
else
_data20_write_char(hidict + addr - LON, value);
}
virtual unsigned long int capacity() const noexcept final {
return LON + HIN;
}
private:
virtual ~SplitMemDictRW() override {};
};
#endif // ALEEFORTH_SPLITMEMDICTRW_HPP

@ -1 +0,0 @@
Subproject commit 45b7ecc1e37d8fdd1bd9a29ec52a15bf7ac69d7f
Loading…
Cancel
Save