176 lines
5.7 KiB
Plaintext
176 lines
5.7 KiB
Plaintext
;; lib/forth/runtime.sx — Forth primitives on SX
|
|
;;
|
|
;; Provides Forth-idiomatic wrappers over SX built-ins.
|
|
;; Primitives used:
|
|
;; bitwise-and/or/xor/not/arithmetic-shift/bit-count (Phase 7)
|
|
;; make-bytevector/bytevector-u8-ref/u8-set!/... (Phase 20)
|
|
;; quotient/remainder/modulo (Phase 15 / builtin)
|
|
;;
|
|
;; Naming: SX identifiers can't include @ or !-alone, so Forth words are:
|
|
;; C@ → forth-cfetch C! → forth-cstore
|
|
;; @ → forth-fetch ! → forth-store
|
|
|
|
;; ---------------------------------------------------------------------------
|
|
;; 1. Bitwise operations — Forth core words
|
|
;; Forth TRUE = -1 (all bits set), FALSE = 0.
|
|
;; All ops coerce to integer via truncate.
|
|
;; ---------------------------------------------------------------------------
|
|
|
|
(define (forth-and a b) (bitwise-and (truncate a) (truncate b)))
|
|
(define (forth-or a b) (bitwise-or (truncate a) (truncate b)))
|
|
(define (forth-xor a b) (bitwise-xor (truncate a) (truncate b)))
|
|
|
|
;; INVERT — bitwise NOT (Forth NOT is logical; INVERT is bitwise)
|
|
(define (forth-invert a) (bitwise-not (truncate a)))
|
|
|
|
;; LSHIFT RSHIFT — n bit — shift a by n positions
|
|
(define (forth-lshift a n) (arithmetic-shift (truncate a) (truncate n)))
|
|
(define
|
|
(forth-rshift a n)
|
|
(arithmetic-shift (truncate a) (- 0 (truncate n))))
|
|
|
|
;; 2* 2/ — multiply/divide by 2 via bit shift
|
|
(define (forth-2* a) (arithmetic-shift (truncate a) 1))
|
|
(define (forth-2/ a) (arithmetic-shift (truncate a) -1))
|
|
|
|
;; BIT-COUNT — number of set bits (Kernighan popcount)
|
|
(define (forth-bit-count a) (bit-count (truncate a)))
|
|
|
|
;; INTEGER-LENGTH — index of highest set bit (0 for zero)
|
|
(define (forth-integer-length a) (integer-length (truncate a)))
|
|
|
|
;; WITHIN — ( u ul uh -- flag ) true if ul <= u < uh
|
|
(define (forth-within u ul uh) (and (>= u ul) (< u uh)))
|
|
|
|
;; Arithmetic complements commonly used alongside bitwise ops
|
|
(define (forth-negate a) (- 0 (truncate a)))
|
|
(define (forth-abs a) (abs (truncate a)))
|
|
(define (forth-min a b) (if (< a b) a b))
|
|
(define (forth-max a b) (if (> a b) a b))
|
|
(define (forth-mod a b) (modulo (truncate a) (truncate b)))
|
|
|
|
;; /MOD — ( n1 n2 -- rem quot ) returns list (remainder quotient)
|
|
(define
|
|
(forth-divmod a b)
|
|
(list
|
|
(remainder (truncate a) (truncate b))
|
|
(quotient (truncate a) (truncate b))))
|
|
|
|
;; ---------------------------------------------------------------------------
|
|
;; 2. String buffer — word-definition / string accumulation
|
|
;; EMIT appends one char; TYPE appends a string.
|
|
;; Value is retrieved with forth-sb-value.
|
|
;; ---------------------------------------------------------------------------
|
|
|
|
(define
|
|
(forth-sb-new)
|
|
(let
|
|
((sb (dict)))
|
|
(dict-set! sb "_forth_sb" true)
|
|
(dict-set! sb "_chars" (list))
|
|
sb))
|
|
|
|
(define (forth-sb? v) (and (dict? v) (dict-has? v "_forth_sb")))
|
|
|
|
;; EMIT — append one character
|
|
(define
|
|
(forth-sb-emit! sb c)
|
|
(dict-set! sb "_chars" (append (get sb "_chars") (list c)))
|
|
sb)
|
|
|
|
;; TYPE — append a string
|
|
(define
|
|
(forth-sb-type! sb s)
|
|
(dict-set! sb "_chars" (append (get sb "_chars") (string->list s)))
|
|
sb)
|
|
|
|
(define (forth-sb-value sb) (list->string (get sb "_chars")))
|
|
|
|
(define (forth-sb-length sb) (len (get sb "_chars")))
|
|
|
|
(define (forth-sb-clear! sb) (dict-set! sb "_chars" (list)) sb)
|
|
|
|
;; Emit integer as decimal digits
|
|
(define (forth-sb-emit-int! sb n) (forth-sb-type! sb (str (truncate n))))
|
|
|
|
;; ---------------------------------------------------------------------------
|
|
;; 3. Memory / Bytevectors — Forth raw memory model
|
|
;; ALLOT allocates a bytevector. Byte and cell (32-bit LE) access.
|
|
;; ---------------------------------------------------------------------------
|
|
|
|
;; ALLOT — allocate n bytes zero-initialised
|
|
(define (forth-mem-new n) (make-bytevector (truncate n) 0))
|
|
|
|
(define (forth-mem? v) (bytevector? v))
|
|
|
|
(define (forth-mem-size v) (bytevector-length v))
|
|
|
|
;; C@ C! — byte fetch/store
|
|
(define (forth-cfetch mem addr) (bytevector-u8-ref mem (truncate addr)))
|
|
|
|
(define
|
|
(forth-cstore mem addr val)
|
|
(bytevector-u8-set!
|
|
mem
|
|
(truncate addr)
|
|
(modulo (truncate val) 256))
|
|
mem)
|
|
|
|
;; @ ! — 32-bit little-endian cell fetch/store
|
|
(define
|
|
(forth-fetch mem addr)
|
|
(let
|
|
((a (truncate addr)))
|
|
(+
|
|
(bytevector-u8-ref mem a)
|
|
(* 256 (bytevector-u8-ref mem (+ a 1)))
|
|
(* 65536 (bytevector-u8-ref mem (+ a 2)))
|
|
(* 16777216 (bytevector-u8-ref mem (+ a 3))))))
|
|
|
|
(define
|
|
(forth-store mem addr val)
|
|
(let
|
|
((a (truncate addr)) (v (truncate val)))
|
|
(bytevector-u8-set! mem a (modulo v 256))
|
|
(bytevector-u8-set!
|
|
mem
|
|
(+ a 1)
|
|
(modulo (quotient v 256) 256))
|
|
(bytevector-u8-set!
|
|
mem
|
|
(+ a 2)
|
|
(modulo (quotient v 65536) 256))
|
|
(bytevector-u8-set!
|
|
mem
|
|
(+ a 3)
|
|
(modulo (quotient v 16777216) 256)))
|
|
mem)
|
|
|
|
;; MOVE — copy count bytes from src[src-addr] to dst[dst-addr]
|
|
(define
|
|
(forth-move! src src-addr dst dst-addr count)
|
|
(letrec
|
|
((go (fn (i) (when (< i (truncate count)) (bytevector-u8-set! dst (+ (truncate dst-addr) i) (bytevector-u8-ref src (+ (truncate src-addr) i))) (go (+ i 1))))))
|
|
(go 0))
|
|
dst)
|
|
|
|
;; FILL — fill count bytes at addr with byte value
|
|
(define
|
|
(forth-fill! mem addr count byte)
|
|
(letrec
|
|
((go (fn (i) (when (< i (truncate count)) (bytevector-u8-set! mem (+ (truncate addr) i) (modulo (truncate byte) 256)) (go (+ i 1))))))
|
|
(go 0))
|
|
mem)
|
|
|
|
;; ERASE — fill with zeros (Forth: ERASE)
|
|
(define
|
|
(forth-erase! mem addr count)
|
|
(forth-fill! mem addr count 0))
|
|
|
|
;; Dump memory region as list of byte values
|
|
(define
|
|
(forth-mem->list mem addr count)
|
|
(letrec
|
|
((go (fn (i acc) (if (= i 0) acc (go (- i 1) (cons (bytevector-u8-ref mem (+ (truncate addr) (- i 1))) acc))))))
|
|
(go (truncate count) (list))))
|