MilliForth-6502:6502架构上最小的Forth语言真实编程实现。
MilliForth-6502: The smallest Forth real programming language for 6502

原始链接: https://github.com/agsb/milliForth-6502

本文件描述了一个针对经典6502 8位CPU的最小化Forth实现,其灵感来自于milliForth和sectorForth等项目。与这些项目(针对x86)不同,本项目专注于6502独特的架构。它探讨了直接线程代码 (DTC) 和最小线程代码 (MTC) 两种内部解释器,最终发现尽管MTC的指令开销更低,但DTC的体积略小。该项目优先考虑代码大小而非性能。 6502 Forth 使用零页存储常用寄存器,并使用从$200页反向增长的堆栈组织内存。它实现了核心Forth原语,例如堆栈操作、内存访问和基本算术运算。该实现包括用于引导、终端交互和外部解释器功能的一套内部函数,并允许扩展功能,例如`bye`、`abort`和堆栈检查。它使用`ca65`编译,并使用`run6502`模拟。一个`my_hello_world.FORTH`脚本用于测试,DTC版本的占用空间约为596字节。

Hacker News 最新 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 MilliForth-6502:6502 最小的 Forth 实用编程语言 (github.com/agsb) 9 分,来自 rbanffy,2 小时前 | 隐藏 | 过去 | 收藏 | 1 评论 cmrdporcupine 1 分钟前 [–] 我敢打赌,他们可以为 6809 编写更小的版本 回复 加入我们 6 月 16-17 日在旧金山举办的 AI 初创公司学校! 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系我们 搜索:

原文

"A Forth in 328 bytes — the smallest real programming language ever, as of yet."

The milliForth1 is a review of sectorForth2, and smaller than sector Lisp3

The miniForth4 is another Forth to use in a boot sector of less than 512 bytes.

Yes, bytes. But those are for a x86 16-bit CPU. How minimal could be it for a classic 6502 8-bit CPU ?

Two essentially different CPUs, a 16-bit x86 based on complex registers and opcodes, and a 8-bit 6502 using page zero as common registers and page one as hardware stack.

The FIG-Forth (1980) for 6502 uses Indirect Thread Code (ITC) as inner interpreter.

The miniForth, sectorforth and milliForth use Direct Thread Code (DTC)

This Forth for 6502, will be was done using two models:

with classic Direct Thread Code (DTC) 
and
with Minimal Thread Code (MTC)

(later we will compare both, but DTC will win for less size)

This project is also used to verify standart Direct Thread Code against variations of Minimum Thread Code.

Minimal Thread Code is an alternative model for inner interpreter, where the dictionary is organized with the primitives words grouped together before the compound words, defining a "tipping point", from where could decide if the reference of a word will be to executed or be pushed into return stack. PS. MTC is a reduced form of TachyonForth inner interpreter.

Focus in size not performance.

The compilation wqas done with ca65 V2.19 - Git 7979f8a41.

The emulation of 6502 CPU was done with run6502

The way at 6502 is use a page zero and lots of lda/sta bytes.

Both DTC and MTC runs with my_hello_world.FORTH, with these numbers.

MTC, Instructions: 35796948, Cycles: 148802145, SIZE: 582

DTC, Instructions: 35211469, Cycles: 148450585, SIZE: 596

compiling my_hello_world.FORTH, overhead MTC / DTC

Instructions:    1.66% 

Cycles:          0.24%

(*) Thanks to wise changes from peterferrie !

  • as Forth-19945: FALSE is $0000 and TRUE is $FFFF ;

  • all tib (80 bytes), pic (16 cells), data (36 cells) and return (36 cells) stacks are in page $200 ;

  • tib and pic grows forward, stacks grows backwards ;

  • only immediate flag used as $80, no more flags ;

  • no line editor, no backspace, no cancel line, no low ASCII verify ;

  • no stacks overflow or underflow checks ;

  • 6502 is a byte processor, no need 'pad' at end of even names ;
  • hardware stack (page $100) not used as forth stack, free for use ;
  • uses 32 bytes of page zero ;
  • no multiuser, no multitask, no faster ;
  • only update latest at end of word definition ;
  • redefine a word does not change previous uses ;
  • stacks moves like the hardware stack ;
  • words must be between spaces, before and after ever ;
  • better use 7-bit ASCII characters ;
  • approuch as ANSI X3.215-19945

Look up at Notes6 for more.

24/08/2024 merge of dtc and mtc code into a flagged sector-6502.s file

16/08/2024: both models DTC and MTC, works with my_hello_world.FORTH;

11/08/2024: return to direct thread code;

11/06/2024: adapt for minimal thread indirect code;

24/01/2024: write using standart direct thread code;

14/11/2023 code for 6502 sized to 624 bytes, no ascii-7, no key, no emit, no 2/, many errors

This version includes:

primitives:
    s@    return the address of user structure
    +     adds two values at top of data stack
    nand  logic not and the two values at top of data stack
    @     fetch a value of cell wich address at top of data stack
    !     store a value into a cell wich address at top of data stack
    0#    test if top of data stack is not zero

    :     starts compilng a new word
    ;     stops compiling a new word
    exit  ends a word

    key   get a char from default terminal (system dependent)
    emit  put a char into default terminal (system dependent)
        
internals: 
    spush, spull, rpull, rpush, (stack code)
    copyfrom, copyinto, (heap code)
    incr, decr, add, etc (register mimics)
    cold, warm, quit, token, skip, scan, getline, (boot and terminal)
    parse, find, compile, execute, (outer interpreter)

    unnest, next, nest, (dtc inner) 
    unnest, next, nest, pick, jump, (mtc inner)

    ps. next is not the FOR NEXT loop    

externals:
    getch, putch, byes (depends on system, used minimal for emulator )

extensions: (selectable)
    2/      shift right one bit
    exec    jump to address at top of spt
    :$      jump to (ipt)   
    ;$      jump to next 

extras:    (selectable)
    bye     ends the Forth, return to system
    abort   restart the Forth
    .S      list cells in data stack
    .R      list cells in return stack
    .       show cell at top of data stack
    words   extended list the words in dictionary
    dump    list contents of dictionary in binary

A my_hello_world.FORTH alternate version with dictionary for use;

The sp@ and rp@ are now derived from s@ in the my_hello_world.FORTH

    $000    page zero       ; cpu reserved
    $100    hardware stack  ; cpu reserved
    $200    TIB             ; terminal input buffer, 80 bytes
    $298*   data stack      ; data stack, 36 cells, backwards
    $2E0*   return stack    ; return stack, 36 cells, backwards
    $2E0    PIC             ; reserved for scratch, 16 cells
    $300    _main_          ; start of Forth
    $???    _ends_          ; end of code and primitives of Forth
    $???    _init_          ; start of compound dictionary

    _init_ is the page (MSB) of _ends_ + 1

" When heap moves forward, move the stack backward "

Push is 'store and decrease'. Pull is 'increas and fetch'.

A common memory model organization of Forth:

   tib->...<-spt, user forth dictionary, here->pad...<-rpt,

then backward stacks allow to use the slack space ...

This 6502 Forth memory model is blocked in pages of 256 bytes:

   page0, page1, page2, core ... forth dictionary ...here...

at page2, without 'rush over'

   |tib 40 cells> <spt 36 cells| <rpt 36 cells|pic 16 cells> | .

"SectorFORTH was an extensive guide throughout the process of implementing milliFORTH, and milliFORTH's design actually converged on sectorFORTH unintentionally in a few areas. That said, the language implemented is intentionally very similar, being the 'minimal FORTH'."

For Forth language primer see Starting Forth

For Forth from inside howto see JonasForth

** 16/08/2024 DTC and MTC models operational, using lib6502 for emulation and tests **

A crude small script for compile with ca65 is included.

; for make it
sh mk a sector-6502

; for clear it
sh mk x sector-6502

the size is take from main: to ends: using the sector-6502.lbl file

the originals files are edited for lines with less than 80 bytes

the bf.FORTH and hello_world.FORTH are from original milliForth1

the my_hello_world.FORTH is adapted for miiliforth-6502

  1. The original milliForth: https://github.com/fuzzballcat/milliForth 2

  2. The inspirational sectorForth: https://github.com/cesarblum/sectorforth/

  3. Mind-blowing sectorLISP: https://justine.lol/sectorlisp2/, https://github.com/jart/sectorlisp

  4. The miniforth: https://github.com/meithecatte/miniforth

  5. Forth standart ANSI X3.215-1994: http://www.forth.org/svfig/Win32Forth/DPANS94.txt 2

  6. Notes and Times: https://github.com/agsb/milliForth-6502/blob/main/Notes.md

联系我们 contact @ memedata.com