1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908 |
- ;;; forth.s
- ;;; based on the public domain eforth implementations
- ;;; found in the files eforth.4th and eforth.S
- ;;; These original implementations are in the Public Domain
- ;;; This is exactly the same as eforth and is not ANSI Forth,
- ;;; although my additions try to follow the ANSI standard
- ;;; This file is placed under a two clause BSD-style license
- ;;; as follows:
- ;;; Copyright 2009 Christopher Hall <hsw@openmoko.com>
- ;;;
- ;;; Redistribution and use in source and binary forms, with or without
- ;;; modification, are permitted provided that the following conditions are
- ;;; met:
- ;;;
- ;;; 1. Redistributions of source code must retain the above copyright
- ;;; notice, this list of conditions and the following disclaimer.
- ;;;
- ;;; 2. 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.
- ;;;
- ;;; THIS SOFTWARE IS PROVIDED BY THE 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 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.
- ;;; symbols used in the ( -- ) comments
- ;;;
- ;;; a aligned address (to 4 byte boundary)
- ;;; b byte address
- ;;; c character
- ;;; ca code address
- ;;; cy carry
- ;;; d signed double integer (2 cells)
- ;;; dirid directory handle (1..n)
- ;;; F logical false (zero)
- ;;; f flag 0 or non-zero
- ;;; fam file access mode
- ;;; fileid file handle (1..n)
- ;;; h half-word address (to 2 byte boundary)
- ;;; ior system dependent error code (zero => no error)
- ;;; la link address
- ;;; n signed integer
- ;;; na name address
- ;;; pa param address
- ;;; T logical true (non-zero)
- ;;; t flag T or F
- ;;; u unsigned integer
- ;;; ud unsigned double integer (2 cells)
- ;;; va vocabulary address
- ;;; w unspecified word value
- ;;;
- ;;; if characters are taken from the input buffer then
- ;;; this form is used
- ;;; ( -- \ <string> ) \ string is terminated by space
- ;;; ( -- \ <string>% ) \ string terminated by %
- ;;; \ % could be any char
- ;;; ( c -- \ <string><char c> )
- ;;; \ string terminated by value of c
- ;;; \ where the character is passed on the stack
- ;;; Version (no minor values, just increment)
- BUILD_NUMBER = 2
- ;;; set this to 1 to diable assembler optimisations
- PREFER_FORTH_CODE = 0
- ;;; some character constants
- backspace = 0x08
- line_feed = 0x0a
- carriage_return = 0x0d
- delete = 0x7f
- ;;; some special constants
- BYTES_PER_CELL = 4
- BITS_PER_BYTE = 8
- BITS_PER_CELL = (BITS_PER_BYTE * BYTES_PER_CELL)
- FALSE = 0
- TRUE = -1
- ;;; header flags
- FLAG_IMMEDIATE = 0x80
- FLAG_COMPILE_ONLY = 0x40
- FLAG_NORMAL = 0
- ;;; registers (C preserves r0..r3)
- ;;; r0 forth ip
- ;;; r1 forth sp
- ;;; r2 forth pp
- ;;; r3 forth w
- ;;; r4 C result low
- ;;; r5 C result high
- ;;; r6 C argument 1
- ;;; r7 C argument 2
- ;;; r8 C argument 3
- ;;; r9 C argument 4
- ;;; r10..r14 used by C and/or extended asm instructions
- ;;; r15 __dp for C
- .macro NEXT ; inner interpreter
- ld.w %r2, [%r0]+ ; incr IP (%r0)
- ld.w %r3, [%r2]+ ; %r2 -> param address
- jp %r3 ; execute the code
- .endm
- ;;; inline forth counted strings
- .macro FSTRING, text
- .byte str_\@_finish - str_\@_start
- str_\@_start:
- .ascii "\text"
- str_\@_finish:
- .balign 4
- .endm
- ;;; macro to create offsets in bytes and cells
- .macro MAKE_OFFSET, label, value
- .ifnotdef \label\()_BYTE
- \label\()_BYTES = \value
- \label\()_CELLS = \value
- .endif
- .endm
- ;;; the header
- ;;; 0: code address
- ;;; 4: param address
- ;;; 8: flags
- ;;; 12: link address
- ;;; 16: count (byte) (name adress points here)
- ;;; 17: name string (count bytes)
- ;;; 17+count: (zeros as required to .balign 4)
- .section .forth_dict, "wa"
- .balign 4
- .section .forth_param, "wax"
- .balign 4
- __last_name = 0 ; to link the list
- .macro HEADER, label, name, flags, code
- .section .forth_dict
- .balign 4
- .global \label
- \label\():
- .long \code ; code
- l_param_\@:
- .long param_\label ; param
- l_flags_\@:
- .long \flags ; flags
- prev_\label = __last_name
- l_link_\@:
- .long prev_\label ; link
- .global name_\label
- name_\label\():
- __last_name = .
- FSTRING "\name"
- MAKE_OFFSET DICTIONARY_HEADER, "( name_\label - \label )"
- MAKE_OFFSET DICTIONARY_CODE_OFFSET, "( name_\label - \label )"
- MAKE_OFFSET DICTIONARY_PARAM_OFFSET, "( name_\label - l_param_\@ )"
- MAKE_OFFSET DICTIONARY_FLAGS_OFFSET, "( name_\label - l_flags_\@ )"
- MAKE_OFFSET DICTIONARY_LINK_OFFSET, "( name_\label - l_link_\@ )"
- .section .forth_param
- .balign 4
- .global param_\label
- param_\label\():
- .endm
- ;;; code definitions
- .macro CODE, label, name, flags
- HEADER \label, "\name", \flags, param_\label
- .endm
- .macro END_CODE
- .endm
- ;;; colon definitions
- .macro COLON, label, name, flags
- HEADER \label, "\name", \flags, param_docolon
- .endm
- ;;; variable definitions
- .macro VARIABLE, label, name, flags
- HEADER \label, "\name", \flags, param_dovar
- .endm
- ;;; constant definitions
- .macro CONSTANT, label, name, flags
- HEADER \label, "\name", \flags, param_doconst
- .endm
- ;;; user variables sections
- .section .user_variables, "wa"
- .balign 4
- user_variables:
- ;;; define user variables
- .macro USER, label, name, flags, defaults
- .section .user_variables
- .global \label\()_variable
- \label\()_variable:
- .long \defaults
- HEADER \label, "\name", \flags, param_douser
- .long \label\()_variable
- .endm
- ;;; miscellaneous variables
- .section .bss
- .balign 4
- terminal_buffer:
- .space 65536
- .global initial_stack_pointer
- initial_stack_pointer: ; NOTE: stack underflows over return space!
- .space 65536
- .global initial_return_pointer
- initial_return_pointer:
- ;;; Program Code
- .section .text
- .global main
- main:
- xld.w %r15, __dp
- xld.w %r1, initial_stack_pointer
- xld.w %r4, initial_return_pointer
- ld.w %sp, %r4
- xld.w %r0, cold_start ; initial ip value
- NEXT
- .balign 4 ; forth byte code must be aligned
- cold_start:
- .long cold, branch, cold_start ; just run cold in a loop
- ;;; .( Special interpreters )
- CODE dolit, "(dolit)", FLAG_COMPILE_ONLY ; ( -- w ) COMPILE-ONLY
- ld.w %r3, [%r0]+
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r3
- NEXT
- END_CODE
- CODE docolon, "(docolon)", FLAG_COMPILE_ONLY ; ( -- )
- pushn %r0 ; save previous ip
- ld.w %r0, [%r2] ; ip = param address
- NEXT
- END_CODE
- CODE execute, "execute", FLAG_NORMAL ; ( a -- )
- ld.w %r2, [%r1]+ ; point to code ptr
- ld.w %r3, [%r2]+ ; code / param address
- jp %r3 ; execute the code
- END_CODE
- CODE exit, "exit", FLAG_NORMAL ; ( -- )
- popn %r0 ; restore ip
- NEXT
- END_CODE
- ;;; .( Loop & Branch - absolute address )
- ;;; : (next) ( -- ) \ hiLevel model 16bit absolute branch
- ;;; r> r> dup if 1- >r @ >r exit then drop cell+ >r ;
- CODE donext, "(next)", FLAG_COMPILE_ONLY
- ld.w %r4, [%sp]
- or %r4, %r4
- jreq donext_l1
- xsub %r4, 1
- ld.w [%sp], %r4
- ld.w %r0, [%r0]
- NEXT
- donext_l1:
- add %sp, 1
- no_branch:
- add %r0, BYTES_PER_CELL
- NEXT
- END_CODE
- CODE qbranch, "?branch", FLAG_COMPILE_ONLY ; ( f -- ) COMPILE-ONLY
- ld.w %r4, [%r1]+
- or %r4, %r4
- jrne no_branch
- ld.w %r0, [%r0]
- NEXT
- END_CODE
- CODE branch, "branch", FLAG_COMPILE_ONLY ; ( -- ) COMPILE-ONLY
- ld.w %r0, [%r0]
- NEXT
- END_CODE
- ;;; .( Memory fetch & store )
- CODE store, "!", FLAG_NORMAL ; ( w a -- )
- ld.w %r4, [%r1]+
- ld.w %r5, [%r1]+
- ld.w [%r4], %r5
- NEXT
- END_CODE
- CODE fetch, "@", FLAG_NORMAL ; ( a -- w )
- ld.w %r4, [%r1]
- ld.w %r4, [%r4]
- ld.w [%r1], %r4
- NEXT
- END_CODE
- CODE hstore, "h!", FLAG_NORMAL ; ( c h -- )
- ld.w %r4, [%r1]+
- ld.w %r5, [%r1]+
- ld.h [%r4], %r5
- NEXT
- END_CODE
- CODE hfetch, "h@", FLAG_NORMAL ; ( h -- c )
- ld.w %r4, [%r1]
- ld.uh %r4, [%r4]
- ld.w [%r1], %r4
- NEXT
- END_CODE
- CODE cstore, "c!", FLAG_NORMAL ; ( c b -- )
- ld.w %r4, [%r1]+
- ld.w %r5, [%r1]+
- ld.b [%r4], %r5
- NEXT
- END_CODE
- CODE cfetch, "c@", FLAG_NORMAL ; ( b -- c )
- ld.w %r4, [%r1]
- ld.ub %r4, [%r4]
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; .( Return Stack )
- CODE rp_fetch, "rp@", FLAG_NORMAL ; ( -- a )
- ld.w %r4, %sp
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- CODE rp_store, "rp!", FLAG_COMPILE_ONLY ; ( a -- ) COMPILE-ONLY
- ld.w %r4, [%r1]+
- ld.w %sp, %r4
- NEXT
- END_CODE
- CODE r_from, "r>", FLAG_COMPILE_ONLY ; ( -- w ) COMPILE-ONLY
- ld.w %r4, [%sp]
- add %sp, 1
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- CODE r_fetch, "r@", FLAG_NORMAL ; ( -- w )
- ld.w %r4, [%sp]
- xsub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- CODE to_r, ">r", FLAG_COMPILE_ONLY ; ( w -- ) COMPILE-ONLY
- ld.w %r4, [%r1]+
- sub %sp, 1
- ld.w [%sp], %r4
- NEXT
- END_CODE
- ;;; .( Data Stack )
- CODE sp_fetch, "sp@", FLAG_NORMAL ; ( -- a )
- ld.w %r4, %r1
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- CODE sp_store, "sp!", FLAG_NORMAL ; ( a -- )
- ld.w %r1, [%r1]
- NEXT
- END_CODE
- CODE drop, "drop", FLAG_NORMAL ; ( w -- )
- ld.w %r4, [%r1]+
- NEXT
- END_CODE
- CODE dup, "dup", FLAG_NORMAL ; ( w -- w w )
- ld.w %r4, [%r1]
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- CODE swap, "swap", FLAG_NORMAL ; ( w1 w2 -- w2 w1 )
- ld.w %r4, [%r1]+
- ld.w %r5, [%r1]+
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r5
- NEXT
- END_CODE
- CODE over, "over", FLAG_NORMAL ; ( w1 w2 -- w1 w2 w1 )
- xld.w %r4, [%r1 + 4]
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : ?DUP ( w -- w w, 0 ) DUP IF DUP THEN ;
- COLON qdup, "?dup", FLAG_NORMAL
- .long dup, qbranch, qdup_l1
- .long dup
- qdup_l1:
- .long exit
- ;;; : NIP ( w1 w2 -- w2 ) SWAP DROP ;
- COLON nip, "nip", FLAG_NORMAL
- .long swap, drop, exit
- ;;; : ROT ( w1 w2 w3 -- w2 w3 w1 ) >R SWAP R> SWAP ;
- COLON rot, "rot", FLAG_NORMAL
- .long to_r, swap, r_from, swap, exit
- ;;; : -ROT ( w1 w2 w3 -- w3 w1 w2 ) ROT ROT ;
- COLON minus_rot, "-rot", FLAG_NORMAL
- .long rot, rot, exit
- ;;; : 2DROP ( w w -- ) DROP DROP ;
- COLON twodrop, "2drop", FLAG_NORMAL
- .long drop, drop, exit
- ;;; : 2DUP ( w1 w2 -- w1 w2 w1 w2 ) OVER OVER ;
- COLON twodup, "2dup", FLAG_NORMAL
- .long over, over, exit
- ;;; .( Logic )
- CODE zero_less, "0<", FLAG_NORMAL ; ( n -- t )
- ld.w %r4, [%r1]
- or %r4, %r4
- jrlt zero_less_l1
- ld.w %r4, FALSE
- ld.w [%r1], %r4
- NEXT
- zero_less_l1:
- ld.w %r4, TRUE
- ld.w [%r1], %r4
- NEXT
- END_CODE
- CODE _and, "and", FLAG_NORMAL ; ( w w -- w )
- ld.w %r4, [%r1]+
- ld.w %r5, [%r1]
- and %r4, %r5
- ld.w [%r1], %r4
- NEXT
- END_CODE
- CODE _or, "or", FLAG_NORMAL ; ( w w -- w )
- ld.w %r4, [%r1]+
- ld.w %r5, [%r1]
- or %r4, %r5
- ld.w [%r1], %r4
- NEXT
- END_CODE
- CODE _xor, "xor", FLAG_NORMAL ; ( w w -- w )
- ld.w %r4, [%r1]+
- ld.w %r5, [%r1]
- xor %r4, %r5
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : INVERT ( w -- w ) -1 XOR ;
- COLON invert, "invert", FLAG_NORMAL
- .long dolit, -1, _xor, exit
- ;;; .( Arithmetic )
- CODE umplus, "um+", FLAG_NORMAL ; ( u u -- u cy ) \ or ( u u -- ud )
- ld.w %r4, [%r1]+
- ld.w %r5, [%r1]
- add %r4, %r5
- ld.w [%r1], %r4
- ld.w %r4, 0
- adc %r4, %r4
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : + ( u u -- u ) UM+ DROP ;
- CODE plus, "+", FLAG_NORMAL ; ( w w -- w )
- ld.w %r4, [%r1]+
- ld.w %r5, [%r1]
- add %r4, %r5
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : 1+ ( w -- w+1 ) 1 + ;
- CODE increment, "1+", FLAG_NORMAL
- ld.w %r4, [%r1]
- xadd %r4, 1
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : 1- ( w -- w-1 ) 1 - ;
- CODE decrement, "1-", FLAG_NORMAL
- ld.w %r4, [%r1]
- xsub %r4, 1
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : NEGATE ( n -- -n ) INVERT 1+ ;
- COLON negate "negate",0
- .long invert, increment, exit
- ;;; : DNEGATE ( d -- -d ) INVERT >R INVERT 1 UM+ R> + ;
- COLON dnegate, "dnegate", FLAG_NORMAL
- .long invert, to_r, invert
- .long dolit, 1, umplus
- .long r_from, plus, exit
- ;;; : - ( w w -- w ) NEGATE + ;
- CODE minus, "-", FLAG_NORMAL ; ( w w -- w )
- ld.w %r5, [%r1]+
- ld.w %r4, [%r1]
- sub %r4, %r5
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : ABS ( n -- +n ) DUP 0< IF NEGATE THEN ;
- COLON abs, "abs", FLAG_NORMAL
- .long dup, zero_less, qbranch, abs_l1
- .long negate
- abs_l1:
- .long exit
- ;;; .( User variables )
- ;;; : (douser) ( -- a ) R> @ UP @ + ; COMPILE-ONLY ( address passed via %r2 not stack )
- CODE douser, "(douser)", FLAG_COMPILE_ONLY
- ld.w %r4, [%r2]
- ld.w %r4, [%r4] ; user is another pointer!
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : (dovar) ( -- a ) R> ; COMPILE-ONLY ( address passed via %r2 not stack )
- CODE dovar, "(dovar)", FLAG_COMPILE_ONLY
- ld.w %r4, [%r2] ; %r4 = parameter address
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : (doconst) ( -- a ) R> @ ; COMPILE-ONLY ( address passed via %r2 not stack )
- CODE doconst, "(doconst)", FLAG_COMPILE_ONLY
- ld.w %r4, [%r2] ; %r4 = parameter address
- ld.w %r4, [%r4] ; read the constant value
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; 8 \ start offset
- USER user_reserved, "(ureserved)", FLAG_NORMAL, "0,0,0,0"
- ;;; DUP USER SP0 1 CELL+ \ initial data stack pointer
- USER sp0, "sp0", FLAG_NORMAL, initial_stack_pointer
- ;;; DUP USER RP0 1 CELL+ \ initial return stack pointer
- USER rp0, "rp0", FLAG_NORMAL, initial_return_pointer
- ;;; DUP USER 'KEY? 1 CELL+ \ character input ready vector
- USER tkey_query, "\047key?", FLAG_NORMAL, rx_query
- ;;; DUP USER 'EMIT 1 CELL+ \ character output vector
- USER temit, "\047emit", FLAG_NORMAL, tx_store
- ;;; DUP USER 'EXPECT 1 CELL+ \ line input vector
- USER texpect, "\047expect", FLAG_NORMAL, accept
- ;;; DUP USER 'TAP 1 CELL+ \ input case vector
- USER ttap, "\047tap", FLAG_NORMAL, ktap
- ;;; DUP USER 'ECHO 1 CELL+ \ input echo vector
- USER techo, "\047echo", FLAG_NORMAL, tx_store
- ;;; DUP USER 'PROMPT 1 CELL+ \ operator prompt vector
- USER tprompt, "\047prompt", FLAG_NORMAL, dot_ok
- ;;; DUP USER BASE 1 CELL+ \ number base
- USER base, "base", FLAG_NORMAL, 10
- ;;; DUP USER temp 1 CELL+ \ scratch
- USER temp, "temp", FLAG_COMPILE_ONLY, 0
- ;;; DUP USER SPAN 1 CELL+ \ #chars input by EXPECT
- USER span, "span", FLAG_NORMAL, 0
- ;;; DUP USER >IN 1 CELL+ \ input buffer offset
- USER to_in, ">in", FLAG_NORMAL, 0
- ;;; DUP USER #TIB 1 CELL+ \ #chars in the input buffer
- ;;; 1 CELLS ALLOT \ address of input buffer
- USER hash_tib, "#tib", FLAG_NORMAL, "0,terminal_buffer"
- ;;; DUP USER UP 1 CELL+ \ user base pointer
- ;; not needed
- ;;; DUP USER CSP 1 CELL+ \ save stack pointers
- ;; not needed
- ;;; DUP USER 'EVAL 1 CELL+ \ interpret/compile vector
- USER teval, "\047eval", FLAG_NORMAL, dollar_interpret
- ;;; DUP USER 'NUMBER 1 CELL+ \ numeric input vector
- USER tnumber, "\047number", FLAG_NORMAL, numberq
- ;;; DUP USER HLD 1 CELL+ \ formated numeric string
- USER hld, "hld", FLAG_NORMAL, 0
- ;;; DUP USER HANDLER 1 CELL+ \ error frame pointer
- USER handler, "handler", FLAG_NORMAL, 0
- ;;; DUP USER CONTEXT 1 CELL+ \ first search vocabulary
- ;;; =VOCS CELL+ \ vocabulary stack
- USER context, "context", FLAG_NORMAL, "0, 0,0,0,0, 0,0,0,0"
- ;;; DUP USER CURRENT 1 CELL+ \ definitions vocabulary
- ;;; 1 CELL+ \ newest vocabulary
- USER current, "current", FLAG_NORMAL, "0,0"
- ;;; DUP USER CP 1 CELL+ \ dictionary code pointer
- ;;; 1 CELL+ \ dictionary name pointer
- ;;; 1 CELL+ \ last name compiled
- USER cp, "cp", FLAG_NORMAL, "end_of_code, end_of_dictionary, last_name"
- ;;; .( Comparison )
- ;;; : 0= ( w -- t ) IF FALSE EXIT THEN TRUE ;
- COLON zero_equal, "0=", FLAG_NORMAL
- .long qbranch, zero_equal_l1
- .long dolit, FALSE, exit
- zero_equal_l1:
- .long dolit, TRUE, exit
- ;;; \ convert any non-zero to a preper TRUE
- ;;; : 0<> ( w -- t ) IF TRUE EXIT THEN FALSE ;
- COLON zero_not_equal, "0<>", FLAG_NORMAL
- .long qbranch, zero_not_equal_l1
- .long dolit, TRUE, exit
- zero_not_equal_l1:
- .long dolit, FALSE, exit
- ;;; : = ( w w -- t ) XOR 0= ;
- COLON equal, "=", FLAG_NORMAL
- .long _xor, zero_equal, exit
- ;;; : U< ( u u -- t ) 2DUP XOR 0< IF NIP 0< EXIT THEN - 0< ;
- COLON uless, "u<", FLAG_NORMAL
- .long twodup, _xor, zero_less, qbranch, uless_l1
- .long nip, zero_less, exit
- uless_l1:
- .long minus, zero_less, exit
- ;;; : U> ( n n -- t ) SWAP U< ;
- COLON ugreater, "u>", FLAG_NORMAL
- .long swap, uless, exit
- ;;; : < ( n n -- t ) 2DUP XOR 0< IF DROP 0< EXIT THEN - 0< ;
- COLON less, "<", FLAG_NORMAL
- .long twodup, _xor, zero_less, qbranch, less_l1
- .long drop, zero_less, exit
- less_l1:
- .long minus, zero_less, exit
- ;;; : > ( n n -- t ) SWAP < ;
- COLON greater, ">", FLAG_NORMAL
- .long swap, less, exit
- ;;; : MAX ( n n -- n ) 2DUP < IF SWAP THEN DROP ;
- COLON max, "max", FLAG_NORMAL
- .long twodup, less, qbranch, max_l1
- .long swap
- max_l1:
- .long drop, exit
- ;;; : MIN ( n n -- n ) 2DUP SWAP < IF SWAP THEN DROP ;
- COLON min, "min", FLAG_NORMAL
- .long twodup, swap, less, qbranch, min_l1
- .long swap
- min_l1:
- .long drop, exit
- ;;; : WITHIN ( u ul uh -- t ) OVER - >R - R> U< ;
- COLON within, "within", FLAG_NORMAL
- .long over, minus, to_r, minus, r_from, uless, exit
- ;;; .( Divide )
- ;;; : UM/MOD ( udl udh un -- ur uq )
- ;;; 2DUP U<
- ;;; IF NEGATE 15
- ;;; FOR >R DUP UM+ >R >R DUP UM+ R> + DUP
- ;;; R> R@ SWAP >R UM+ R> OR
- ;;; IF >R DROP 1+ R> ELSE DROP THEN R>
- ;;; NEXT DROP SWAP EXIT
- ;;; THEN DROP 2DROP -1 DUP ;
- COLON um_slash_mod, "um/mod", FLAG_NORMAL
- .long twodup, uless
- .long qbranch, um_slash_mod_l4
- .long negate, dolit, BITS_PER_CELL - 1, to_r
- um_slash_mod_l1:
- .long to_r, dup, umplus
- .long to_r, to_r, dup, umplus
- .long r_from, plus, dup
- .long r_from, r_fetch, swap, to_r
- .long umplus, r_from, _or
- .long qbranch, um_slash_mod_l2
- .long to_r, drop, dolit, 1, plus, r_from
- .long branch, um_slash_mod_l3
- um_slash_mod_l2:
- .long drop
- um_slash_mod_l3:
- .long r_from
- .long donext, um_slash_mod_l1
- .long drop, swap, exit
- um_slash_mod_l4:
- .long drop, twodrop
- .long dolit, -1, dup, exit
- ;;; : M/MOD ( d n -- r q ) \ floored
- ;;; DUP 0< DUP >R
- ;;; IF NEGATE >R DNEGATE R>
- ;;; THEN >R DUP 0< IF R@ + THEN R> UM/MOD R>
- ;;; IF SWAP NEGATE SWAP THEN ;
- COLON m_slash_mod, "m/mod", 0
- .long dup, zero_less, dup, to_r
- .long qbranch, m_slash_mod_l1
- .long negate, to_r, dnegate, r_from
- m_slash_mod_l1:
- .long to_r, dup, zero_less
- .long qbranch, m_slash_mod_l2
- .long r_fetch, plus
- m_slash_mod_l2:
- .long r_from, um_slash_mod, r_from
- .long qbranch, m_slash_mod_l3
- .long swap, negate, swap
- m_slash_mod_l3:
- .long exit
- ;;; : /MOD ( n n -- r q ) OVER 0< SWAP M/MOD ;
- COLON slash_mod, "/mod", FLAG_NORMAL
- .long over, zero_less, swap, m_slash_mod, exit
- ;;; : MOD ( n n -- r ) /MOD DROP ;
- COLON mod, "mod", FLAG_NORMAL
- .long slash_mod, drop, exit
- ;;; : / ( n n -- q ) /MOD NIP ;
- COLON divide, "/", FLAG_NORMAL
- .long slash_mod, nip, exit
- ;;; .( Multiply )
- ;;; : UM* ( u1 u2 -- ud )
- ;;; 0 SWAP ( u1 0 u2 ) 15
- ;;; FOR DUP UM+ >R >R DUP UM+ R> + R>
- ;;; IF >R OVER UM+ R> + THEN
- ;;; NEXT ROT DROP ;
- CODE umult, "um*", FLAG_NORMAL
- ld.w %r4, [%r1]+
- ld.w %r5, [%r1]
- mltu.w %r4, %r5
- ld.w %r4, %alr
- ld.w [%r1], %r4
- sub %r1, BYTES_PER_CELL
- ld.w %r4, %ahr
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : * ( n n -- n ) UM* DROP ;
- CODE times, "*", FLAG_NORMAL
- ld.w %r4, [%r1]+
- ld.w %r5, [%r1]
- mlt.w %r4, %r5
- ld.w %r4, %alr
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : M* ( n n -- d )
- ;;; 2DUP XOR 0< >R ABS SWAP ABS UM* R> IF DNEGATE THEN ;
- CODE multd, "m*", FLAG_NORMAL
- ld.w %r4, [%r1]+
- ld.w %r5, [%r1]
- mlt.w %r4, %r5
- ld.w %r4, %alr
- ld.w [%r1], %r4
- ld.w %r4, %ahr
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : */MOD ( n n n -- r q ) >R M* R> M/MOD ;
- ;;; : */ ( n n n -- q ) */MOD NIP ;
- ;;; .( bit shifts )
- ;;; : 2* 2 * ;
- CODE _shl, "2*", FLAG_NORMAL
- ld.w %r4, [%r1]
- sla %r4, 1
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : 2/ 2 / ;
- CODE _shra, "2/", FLAG_NORMAL
- ld.w %r4, [%r1]
- sra %r4, 1
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : LSHIFT ( u u -- u ) UM+ DROP ;
- CODE lshift, "lshift", FLAG_NORMAL ; ( w u -- w )
- ld.w %r4, [%r1]+ ; shift
- ld.w %r5, [%r1] ; value
- sla %r5, %r4
- ld.w [%r1], %r5
- NEXT
- END_CODE
- ;;; : RSHIFT ( u u -- u ) UM+ DROP ;
- CODE rshift, "rshift", FLAG_NORMAL ; ( w u -- w )
- ld.w %r4, [%r1]+ ; shift
- ld.w %r5, [%r1] ; value
- srl %r5, %r4
- ld.w [%r1], %r5
- NEXT
- END_CODE
- ;;; .( Bits & Bytes )
- ;;; : CHAR+ ( b -- b ) [ =BYTE ] LITERAL + ;
- COLON char_plus, "char+", FLAG_NORMAL
- .long increment, exit
- ;;; : CHAR- ( b -- b ) [ =BYTE ] LITERAL - ;
- COLON char_minus, "char-", FLAG_NORMAL
- .long decrement, exit
- ;;; : BYTE+ ( b -- b ) [ =BYTE ] LITERAL + ;
- COLON byte_plus, "byte+", FLAG_NORMAL
- .long increment, exit
- ;;; : BYTE- ( b -- b ) [ =BYTE ] LITERAL - ;
- COLON byte_minus, "byte-", FLAG_NORMAL
- .long decrement, exit
- ;;; : CELL+ ( a -- a ) [ =CELL ] LITERAL + ;
- COLON cell_plus, "cell+", FLAG_NORMAL
- .long dolit, BYTES_PER_CELL, plus, exit
- ;;; : CELL- ( a -- a ) [ =CELL ] LITERAL - ;
- COLON cell_minus, "cell-", FLAG_NORMAL
- .long dolit, BYTES_PER_CELL, minus, exit
- ;;; : CELLS ( n -- n ) [ =CELL ] LITERAL * ;
- COLON cells, "cells", FLAG_NORMAL
- .long dolit, BYTES_PER_CELL, times, exit
- ;;; : BL ( -- 32 ) 32 ;
- COLON blank, "bl", FLAG_NORMAL
- .long dolit, 32, exit
- ;;; \ subsitute unprintable character with '.'
- ;;; : >CHAR ( c -- c )
- ;;; 127 AND DUP 127 BL WITHIN IF DROP [CHAR] . THEN ;
- COLON to_char, ">char", FLAG_NORMAL
- .long dolit, 0x7f, _and, dup
- .long dolit, 0x7f, blank, within
- .long qbranch, to_char_l1
- .long drop, dolit, '.'
- to_char_l1:
- .long exit
- ;;; : CHAR>LOWER ( c -- c )
- ;;; DUP [CHAR] A [ CHAR Z 1+ ] LITERAL WITHIN
- ;;; IF [ CHAR a CHAR A - ] LITERAL + THEN ;
- COLON char_to_lower, "char>lower", FLAG_NORMAL
- .long dup, dolit, 'A', dolit, 'Z' + 1, within
- .long qbranch, char_to_lower_l1
- .long dolit, 'a' - 'A', plus
- char_to_lower_l1:
- .long exit
- ;;; : CHAR>UPPER ( c -- c )
- ;;; DUP [CHAR] a [ CHAR z 1+ ] LITERAL WITHIN
- ;;; IF [ CHAR A CHAR a - ] LITERAL + THEN ;
- COLON char_to_upper, "char>upper", FLAG_NORMAL
- .long dup, dolit, 'a', dolit, 'z' + 1, within
- .long qbranch, char_to_upper_l1
- .long dolit, 'A' - 'a', plus
- char_to_upper_l1:
- .long exit
- ;;; : DEPTH ( -- n ) SP@ SP0 @ SWAP - 1 CELLS / ;
- COLON depth, "depth", FLAG_NORMAL
- .long sp_fetch, sp0, fetch, swap, minus
- .long dolit, 1, cells, divide, exit
- ;;; : PICK ( +n -- w ) 1+ CELLS SP@ + @ ;
- COLON pick, "pick", FLAG_NORMAL
- .long increment, cells, sp_fetch, plus, fetch, exit
- ;;; align to a CELL boundary
- ;;; : ALIGNED ( b -- a ) ; IMMEDIATE
- COLON aligned, "aligned", FLAG_IMMEDIATE
- .long dolit, BYTES_PER_CELL - 1, plus
- .long dolit, -BYTES_PER_CELL, _and, exit
- ;;; .( Memory access )
- ;;; : +! ( n a -- ) SWAP OVER @ + SWAP ! ;
- COLON plus_store, "+!", FLAG_NORMAL
- .long swap, over, fetch, plus, swap, store, exit
- ;;; : 2! ( d a -- ) SWAP OVER ! CELL+ ! ;
- COLON dstore, "2!", FLAG_NORMAL
- .long swap, over, store, cell_plus, store, exit
- ;;; : 2@ ( a -- d ) DUP CELL+ @ SWAP @ ;
- COLON dfetch, "2@", FLAG_NORMAL
- .long dup, cell_plus, fetch, swap, fetch, exit
- ;;; : COUNT ( b -- b +n ) DUP BYTE+ SWAP C@ ;
- COLON count, "count", FLAG_NORMAL
- .long dup, byte_plus, swap, cfetch, exit
- ;;; : HERE ( -- a ) CP @ ;
- COLON here, "here", FLAG_NORMAL
- .long cp, fetch, exit
- ;;; : PAD ( -- a ) HERE 80 + ;
- COLON pad, "pad", FLAG_NORMAL
- .long here, dolit, 80, plus, exit
- ;;; : TIB ( -- a ) #TIB CELL+ @ ;
- COLON tib, "tib", FLAG_NORMAL
- .long hash_tib, cell_plus, fetch, exit
- ;;; : NP ( -- a ) CP CELL+ ;
- COLON np, "np", FLAG_NORMAL
- .long cp, cell_plus, exit
- ;;; : LAST ( -- a ) NP CELL+ ;
- COLON last, "last", FLAG_NORMAL
- .long np, cell_plus, exit
- ;;; : (dovoc) ( -- ) R> CONTEXT ! ; COMPILE-ONLY
- COLON dovoc, "(dovoc)", FLAG_COMPILE_ONLY
- .long r_from, context, store, exit
- ;;; \ Make FORTH the context vocabulary
- ;;; : FORTH ( -- ) COMPILE (dovoc) [ =HEAD ] , [ =LINK ] , ;
- COLON forth, "forth", FLAG_NORMAL
- .long dovoc
- .long last_name ; vocabulary head pointer
- .long last_name ; vocabulary link pointer
- ;;; : @EXECUTE ( a -- ) @ ?DUP IF EXECUTE THEN ;
- COLON atexecute, "@execute", FLAG_NORMAL
- .long fetch, qdup, qbranch, atexecute_l1
- .long execute
- atexecute_l1:
- .long exit
- ;;; : CMOVE ( b b u -- )
- ;;; FOR AFT >R COUNT R@ C! R> 1+ THEN NEXT 2DROP ;
- CODE cmove, "cmove", FLAG_NORMAL
- ld.w %r4, [%r1]+ ; count
- ld.w %r5, [%r1]+ ; dst
- ld.w %r6, [%r1]+ ; src
- or %r4, %r4
- jreq cmove_done
- cmove_loop:
- ld.ub %r7, [%r6]+
- ld.b [%r5]+, %r7
- xsub %r4, 1
- jrne cmove_loop
- cmove_done:
- NEXT
- END_CODE
- ;;; \ compile to memory blocks
- ;;; : MEM= ( b b u -- f )
- CODE mem_equal, "mem=", FLAG_NORMAL
- ld.w %r4, [%r1]+ ; count
- ld.w %r5, [%r1]+ ; addr 2
- ld.w %r6, [%r1] ; addr 1
- or %r4, %r4
- jreq mem_equal_true
- mem_equal_loop:
- ld.ub %r7, [%r6]+
- ld.ub %r8, [%r5]+
- cmp %r7, %r8
- jrne mem_equal_false
- xsub %r4, 1
- jrne mem_equal_loop
- mem_equal_true:
- ld.w %r4, TRUE
- ld.w [%r1], %r4
- NEXT
- END_CODE
- mem_equal_false:
- ld.w %r4, FALSE
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : -TRAILING ( b u -- b u )
- ;;; FOR AFT DUP R@ + C@ BL XOR
- ;;; IF R> BYTE+ EXIT THEN THEN
- ;;; NEXT 0 ;
- COLON minus_trailing, "-trailing", FLAG_NORMAL
- .long to_r
- minus_trailing_l1:
- .long dup, r_fetch, plus, cfetch, blank, _xor
- .long qbranch, minus_trailing_l2
- .long r_from, byte_plus, exit
- minus_trailing_l2:
- .long donext, minus_trailing_l1
- .long dolit, 0, exit
- ;;; : FILL ( b u c -- )
- ;;; SWAP FOR SWAP AFT 2DUP C! BYTE+ THEN NEXT 2DROP ;
- COLON fill, "fill", FLAG_NORMAL
- .long swap, to_r, swap
- fill_l1:
- .long twodup, cstore, byte_plus
- .long donext, fill_l1
- .long twodrop, exit
- ;;; : ERASE ( b u -- ) 0 FILL ;
- COLON erase, "erase", FLAG_NORMAL
- .long dolit, 0, fill, exit
- ;;; : PACK$ ( b u a -- a ) \ null terminated
- ;;; DUP >R 2DUP C! BYTE+ SWAP CMOVE R> ;
- COLON pack_dollar, "pack$", FLAG_NORMAL
- .long aligned, dup, to_r
- .long twodup, cstore, byte_plus
- .long swap, cmove, r_from, exit
- ;;; .( stack handling )
- ;;; \ usage example:
- ;;; \ 25 ( stack-size-in-cells )
- ;;; \ dup create my-stack 2 + cells allot
- ;;; \ mystack !
- ;;; \ stack = {size(N), ptr, value1, value2, ..., valueN}
- ;;; : stack-clear ( a -- )
- ;;; cell+ 0 swap ! ;
- COLON stack_clear, "stack-clear", FLAG_NORMAL
- .long cell_plus, dolit, 0, swap, store, exit
- ;;; : STACK-PUSH ( w a -- )
- ;;; DUP \ w a a
- ;;; @ \ w a size
- ;;; SWAP CELL+ \ w size ptr
- ;;; >R R@ @ 1+ \ w size index
- ;;; SWAP OVER \ w index size index
- ;;; < ABORT" stack overflow"
- ;;; \ w index
- ;;; DUP R@ ! \ w index
- ;;; CELLS R> + !
- ;;; ;
- COLON stack_push, "stack-push", FLAG_NORMAL
- .long dup, fetch, swap, cell_plus
- .long to_r, r_fetch, fetch, increment
- .long swap, over, less
- .long do_abort_quote
- FSTRING "stack overflow"
- .long dup, r_fetch, store
- .long cells, r_from, plus, store
- .long exit
- ;;; : STACK-POP ( a -- w )
- ;;; CELL+ >R R@ @ 1- DUP 0< abort" stack underflow"
- ;;; DUP R@ ! 1+ CELLS R> + @
- ;;; ;
- COLON stack_pop, "stack-pop", FLAG_NORMAL
- .long cell_plus, to_r, r_fetch, fetch
- .long decrement, dup, zero_less
- .long do_abort_quote
- FSTRING "stack underflow"
- .long dup, r_fetch, store, increment
- .long cells, r_from, plus, fetch
- .long exit
- ;;; .( Numeric Output ) \ single precision
- ;;; : DIGIT ( u -- c ) 9 OVER < 7 AND + [CHAR] 0 + ;
- COLON digit, "digit", FLAG_NORMAL
- .long dolit, 9, over, less, dolit, 7, _and, plus, dolit, '0', plus, exit
- ;;; : EXTRACT ( n base -- n c ) 0 SWAP UM/MOD SWAP DIGIT ;
- COLON extract, "extract", FLAG_NORMAL
- .long dolit, 0, swap, um_slash_mod, swap, digit, exit
- ;;; : <# ( -- ) PAD HLD ! ;
- COLON less_hash, "<#", FLAG_NORMAL
- .long pad, hld, store, exit
- ;;; : HOLD ( c -- ) HLD @ BYTE- DUP HLD ! C! ;
- COLON hold, "hold", FLAG_NORMAL
- .long hld, fetch, byte_minus, dup, hld, store, cstore, exit
- ;;; : # ( u -- u ) BASE @ EXTRACT HOLD ;
- COLON hash, "#", FLAG_NORMAL
- .long base, fetch, extract, hold, exit
- ;;; : #S ( u -- 0 ) BEGIN # DUP WHILE REPEAT ;
- COLON hash_s, "#s", FLAG_NORMAL
- hash_s_l1:
- .long hash, dup
- .long qbranch, hash_s_l2
- .long branch, hash_s_l1
- hash_s_l2:
- .long exit
- ;;; : SIGN ( n -- ) 0< IF [CHAR] - HOLD THEN ;
- COLON sign, "sign", FLAG_NORMAL
- .long zero_less, qbranch, sign_l1
- .long dolit, '-', hold
- sign_l1:
- .long exit
- ;;; : #> ( w -- b u ) DROP HLD @ PAD OVER - ;
- COLON hash_greater, "#>", FLAG_NORMAL
- .long drop, hld, fetch, pad, over, minus, exit
- ;;; : (str) ( w -- b u ) DUP >R ABS <# #S R> SIGN #> ;
- COLON paren_str, "(str)"
- .long dup, to_r, abs, less_hash, hash_s, r_from, sign, hash_greater, exit
- ;;; : HEX ( -- ) 16 BASE ! ;
- COLON hex, "hex", FLAG_NORMAL
- .long dolit, 16, base, store, exit
- ;;; : DECIMAL ( -- ) 10 BASE ! ;
- COLON decimal, "decimal", FLAG_NORMAL
- .long dolit, 10, base, store, exit
- ;;; .( Numeric Input ) \ single precision
- ;;; : DIGIT? ( c base -- u t )
- ;;; >R CHAR>UPPER [CHAR] 0 - 9 OVER <
- ;;; IF 7 - DUP 10 < OR THEN DUP R> U< ;
- COLON digitq, "digit?", FLAG_NORMAL
- .long to_r, char_to_lower, dolit, '0', minus
- .long dolit, 9, over, less
- .long qbranch, digitq_l1
- .long dolit, 'a' - '0' - 10, minus ;*lower case*
- .long dup, dolit, 10, less, _or
- digitq_l1:
- .long dup, r_from, uless, exit
- ;;; : NUMBER? ( a -- n T, a F )
- ;;; BASE @ >R 0 OVER COUNT ( a 0 b n)
- ;;; OVER C@ [CHAR] $ =
- ;;; IF HEX SWAP BYTE+ SWAP 1- THEN ( a 0 b' n')
- ;;; OVER C@ [CHAR] - = >R ( a 0 b n)
- ;;; SWAP R@ - SWAP R@ + ( a 0 b" n") ?DUP
- ;;; IF 1- ( a 0 b n)
- ;;; FOR DUP >R C@ BASE @ DIGIT?
- ;;; WHILE SWAP BASE @ * + R> BYTE+
- ;;; NEXT R@ ( ?sign) NIP ( b) IF NEGATE THEN SWAP
- ;;; ELSE R> R> ( b index) 2DROP ( digit number) 2DROP 0
- ;;; THEN DUP
- ;;; THEN R> ( n ?sign) 2DROP R> BASE ! ;
- COLON numberq, "number?", FLAG_NORMAL
- .long base, fetch, to_r, dolit, 0, over, count
- .long over, cfetch, dolit, '$', equal
- .long qbranch, numberq_l1
- .long hex, swap, byte_plus
- .long swap, decrement
- numberq_l1:
- .long over, cfetch, dolit, '-', equal, to_r
- .long swap, r_fetch, minus, swap, r_fetch, plus, qdup
- .long qbranch, numberq_l6
- .long decrement, to_r
- numberq_l2:
- .long dup, to_r, cfetch, base, fetch, digitq
- .long qbranch, numberq_l4
- .long swap, base, fetch, times, plus, r_from
- .long byte_plus
- .long donext, numberq_l2
- .long r_fetch, swap, drop
- .long qbranch, numberq_l3
- .long negate
- numberq_l3:
- .long swap
- .long branch, numberq_l5
- numberq_l4:
- .long r_from, r_from, twodrop, twodrop, dolit, 0
- numberq_l5:
- .long dup
- numberq_l6:
- .long r_from, twodrop
- .long r_from, base, store, exit
- ;;; .( Basic I/O )
- ;;; : KEY? ( -- c T | F ) 'KEY? @EXECUTE ;
- COLON key_query, "key?", FLAG_NORMAL
- .long tkey_query, atexecute, exit
- ;;; : KEY ( -- c ) BEGIN KEY? UNTIL ;
- COLON key, "key", FLAG_NORMAL
- key_l1:
- .long key_query, qbranch, key_l1, exit
- ;;; : EMIT ( c -- ) 'EMIT @EXECUTE ;
- COLON emit, "emit", FLAG_NORMAL
- .long temit, atexecute, exit
- ;;; if key is pressed, wait for second key press
- ;;; return true if the second key is enter
- ;;; : ENOUGH? ( -- f ) KEY? DUP IF 2DROP KEY 13 = THEN ;
- COLON enoughq, "enough?", FLAG_NORMAL
- .long key_query, dup
- .long qbranch, enoughq_l1
- .long twodrop, key, dolit, 13, equal
- enoughq_l1:
- .long exit
- ;;; : SPACE ( -- ) BL EMIT ;
- COLON space, "space", FLAG_NORMAL
- .long blank, emit, exit
- ;;; : CHARS ( +n c -- ) SWAP 0 MAX FOR AFT DUP EMIT THEN NEXT DROP ;
- COLON chars, "chars", FLAG_NORMAL
- .long swap, dolit, 0, max
- .long to_r, branch, chars_l2
- chars_l1:
- .long dup, emit
- chars_l2:
- .long donext, chars_l1
- .long drop, exit
- ;;; : SPACES ( +n -- ) BL CHARS ;
- COLON spaces, "spaces", FLAG_NORMAL
- .long blank, chars, exit
- ;;; : do$ ( -- a )
- ;;; R> R@ R> COUNT + ALIGNED >R SWAP >R ; COMPILE-ONLY
- COLON do_dollar, "do$", FLAG_COMPILE_ONLY
- .long r_from, r_fetch, r_from, count, plus
- .long aligned, to_r, swap, to_r, exit
- ;;; : ($") ( -- a ) do$ ; COMPILE-ONLY
- COLON do_dollar_quote, "($\042)", FLAG_COMPILE_ONLY
- .long do_dollar, exit
- ;;; : TYPE ( b u -- ) FOR AFT COUNT EMIT THEN NEXT DROP ;
- COLON type, "type", FLAG_NORMAL
- .long to_r
- .long branch, type_l2
- type_l1:
- .long dup, cfetch, emit, increment
- type_l2:
- .long donext, type_l1
- .long drop, exit
- ;;; : .$ ( a -- ) COUNT TYPE ;
- COLON dot_dollar, ".$", FLAG_NORMAL
- .long count, type, exit
- ;;; : (.") ( -- ) do$ .$ ; COMPILE-ONLY
- COLON do_dot_quote, "(.\042)", FLAG_COMPILE_ONLY
- .long do_dollar, dot_dollar, exit
- ;;; : CR ( -- ) 13 EMIT 10 EMIT ;
- COLON cr, "cr", FLAG_NORMAL
- .long dolit, carriage_return, emit
- .long dolit, line_feed, emit, exit
- ;;; : .R ( n +n -- ) >R (str) R> OVER - SPACES TYPE ;
- COLON dot_r, ".r", FLAG_NORMAL
- .long to_r, paren_str, r_from, over, minus, spaces, type, exit
- ;;; : U.R ( u +n -- ) >R <# #S #> R> OVER - SPACES TYPE ;
- COLON u_dot_r, "u.r", FLAG_NORMAL
- .long to_r, less_hash, hash_s, hash_greater, r_from, over, minus, spaces, type, exit
- ;;; : U. ( u -- ) <# #S #> SPACE TYPE ;
- COLON u_dot, "u.", FLAG_NORMAL
- .long less_hash, hash_s, hash_greater, space, type, exit
- ;;; : . ( w -- ) BASE @ 10 XOR IF U. EXIT THEN (str) SPACE TYPE ;
- COLON dot, ".", FLAG_NORMAL
- .long base, fetch, dolit, 10, _xor
- .long qbranch, dot_l1
- .long u_dot, exit
- dot_l1:
- .long paren_str, space, type, exit
- ;;; : DEC. ( w -- ) \ decimal display
- ;;; BASE @ DECIMAL SWAP . BASE ! ;
- COLON dec_dot, "dec.", FLAG_NORMAL
- .long base, fetch, decimal, swap, dot, base, store, exit
- ;;; : HEX. ( w -- ) \ hexadecimal display
- ;;; BASE @ HEX SWAP . BASE ! ;
- COLON hex_dot, "hex.", FLAG_NORMAL
- .long base, fetch, hex, swap, dot, base, store, exit
- ;;; : ? ( a -- ) @ . ;
- COLON question, "?", FLAG_NORMAL
- .long fetch, dot, exit
- ;;; : H? ( h -- ) H@ . ;
- COLON hquestion, "h?", FLAG_NORMAL
- .long hfetch, dot, exit
- ;;; : C? ( b -- ) C@ . ;
- COLON cquestion, "c?", FLAG_NORMAL
- .long cfetch, dot, exit
- ;;; .( Parsing )
- ;;; : (parse) ( b u c -- b u delta \ <string><char c> )
- ;;; temp ! OVER >R DUP \ b u u
- ;;; IF 1- temp @ BL =
- ;;; IF \ b u' \ 'skip'
- ;;; FOR COUNT temp @ SWAP - 0< INVERT WHILE
- ;;; NEXT ( b) R> DROP 0 DUP EXIT \ all delim
- ;;; THEN 1- R>
- ;;; THEN OVER SWAP \ b' b' u' \ 'scan'
- ;;; FOR COUNT temp @ SWAP - temp @ BL =
- ;;; IF 0< THEN WHILE
- ;;; NEXT DUP >R ELSE R> DROP DUP >R 1-
- ;;; THEN OVER - R> R> - EXIT
- ;;; THEN ( b u) OVER R> - ;
- COLON paren_parse, "(parse)", FLAG_NORMAL
- .long temp, store, over, to_r, dup
- .long qbranch, paren_parse_l8
- .long decrement, temp, fetch, blank, equal
- .long qbranch, paren_parse_l3
- .long to_r
- paren_parse_l1:
- .long blank, over, cfetch
- .long minus, zero_less, invert
- .long qbranch, paren_parse_l2
- .long increment
- .long donext, paren_parse_l1
- .long r_from, drop, dolit, 0, dup, exit
- paren_parse_l2:
- .long r_from
- paren_parse_l3:
- .long over, swap
- .long to_r
- paren_parse_l4:
- .long temp, fetch, over, cfetch, minus
- .long temp, fetch, blank, equal
- .long qbranch, paren_parse_l5
- .long zero_less
- paren_parse_l5:
- .long qbranch, paren_parse_l6
- .long increment
- .long donext, paren_parse_l4
- .long dup, to_r
- .long branch, paren_parse_l7
- paren_parse_l6:
- .long r_from, drop, dup
- .long increment, to_r
- paren_parse_l7:
- .long over, minus
- .long r_from, r_from, minus, exit
- paren_parse_l8:
- .long over, r_from, minus, exit
- ;;; : PARSE ( c -- b u \ <string> )
- ;;; >R TIB >IN @ + #TIB @ >IN @ - R> (parse) >IN +! ;
- COLON parse, "parse", FLAG_NORMAL
- .long to_r, tib, to_in, fetch, plus
- .long hash_tib, fetch, to_in, fetch, minus
- .long r_from, paren_parse
- .long to_in, plus_store, exit
- ;;; : .( ( -- ) [CHAR] ) PARSE CR TYPE ; IMMEDIATE
- COLON dot_paren, ".(", FLAG_IMMEDIATE
- .long dolit, ')', parse, cr, type, exit
- ;;; : ( ( -- ) [CHAR] ) PARSE 2DROP ; IMMEDIATE
- COLON paren, "(", FLAG_IMMEDIATE
- .long dolit, ')', parse, twodrop, exit
- ;;; : \ ( -- ) #TIB @ >IN ! ; IMMEDIATE
- COLON backslash, "\\", FLAG_IMMEDIATE
- .long hash_tib, fetch, to_in, store, exit
- ;;; : CHAR ( -- c ) BL PARSE DROP C@ ;
- COLON char, "char", FLAG_NORMAL
- .long blank, parse, drop, cfetch, exit
- ;;; : [CHAR] ( -- c ) CHAR LITERAL ; FLAG_IMMEDIATE FLAG_COMPILE_ONLY
- COLON bracket_char, "[char]", FLAG_IMMEDIATE + FLAG_COMPILE_ONLY
- .long char, literal, exit
- ;;; : CTRL ( -- c ) CHAR $001F AND ;
- COLON ctrl, "ctrl", FLAG_NORMAL
- .long char, dolit, 0x1f, _and, exit
- ;;; : [CTRL] ( -- c ) CTRL LITERAL ; FLAG_IMMEDIATE FLAG_COMPILE_ONLY
- COLON bracket_ctrl, "[ctrl]", FLAG_IMMEDIATE + FLAG_COMPILE_ONLY
- .long ctrl, literal, exit
- ;;; this puts the name in the right place for being the next defined item
- ;;; : TOKEN ( -- a \ <string> ) \ and reserve space for dictionary header
- ;;; BL PARSE 31 MIN NP @ [ =DICTIONARY-HEADER-CELLS ] CELLS + PACK$ ;
- COLON token, "token", FLAG_NORMAL
- .long blank, parse
- .long dolit, 31, min
- .long np, fetch, dolit, DICTIONARY_HEADER_CELLS, cells, plus, pack_dollar
- .long exit
- ;;; : WORD ( c -- a \ <string> ) PARSE HERE PACK$ ;
- COLON word, "word", FLAG_NORMAL
- .long parse, here, pack_dollar, exit
- ;;; .( Dictionary Search )
- ;;; : NAME>CODE ( na -- ca ) [ =DICTIONARY-CODE-OFFSET ] LITERAL CELLS - ;
- COLON name_to_code, "name>code", FLAG_NORMAL
- .long dolit, DICTIONARY_CODE_OFFSET_BYTES, minus, exit
- ;;; : NAME>PARAM ( na -- pa ) [ =DICTIONARY-PARAM-OFFSET ] LITERAL CELLS - ;
- COLON name_to_param, "name>param", FLAG_NORMAL
- .long dolit, DICTIONARY_PARAM_OFFSET_BYTES, minus, exit
- ;;; : NAME>FLAGS ( na -- fa ) [ =DICTIONARY-FLAGS-OFFSET ] LITERAL CELLS - ;
- COLON name_to_flags, "name>flags", FLAG_NORMAL
- .long dolit, DICTIONARY_FLAGS_OFFSET_BYTES, minus, exit
- ;;; : NAME>LINK ( na -- la ) [ =DICTIONARY-LINK-OFFSET ] LITERAL CELLS - ;
- COLON name_to_link, "name>link", FLAG_NORMAL
- .long dolit, DICTIONARY_LINK_OFFSET_BYTES, minus, exit
- ;;; : CODE>NAME ( ca -- na ) [ =DICTIONARY-CODE-OFFSET ] LITERAL CELLS + ;
- COLON code_to_name, "code>name", FLAG_NORMAL
- .long dolit, DICTIONARY_CODE_OFFSET_BYTES, plus, exit
- ;;; return TRUE if counted strings are equal
- ;;; : SAME? ( a a -- a a f )
- ;;; 2DUP COUNT NIP SWAP COUNT NIP 2DUP =
- ;;; IF DROP \ a a u
- ;;; FOR AFT OVER R@ + BYTE+ C@
- ;;; OVER R@ + BYTE+ C@ XOR
- ;;; IF R> DROP FALSE EXIT THEN THEN
- ;;; NEXT TRUE
- ;;; ELSE 2DROP FALSE
- ;;; THEN ;
- .if PREFER_FORTH_CODE
- COLON sameq, "same?", FLAG_NORMAL
- .long twodup, count, nip, swap, count, nip, twodup, equal
- .long qbranch, same_l3
- .long drop, to_r
- .long branch, same_l2
- same_l1:
- .long over, r_fetch, plus, byte_plus, cfetch
- .long over, r_fetch, plus, byte_plus, cfetch
- .long _xor
- .long qbranch, same_l2
- .long r_from, drop, dolit, FALSE, exit
- same_l2:
- .long donext, same_l1
- .long dolit, TRUE, exit
- same_l3:
- .long twodrop, dolit, FALSE, exit
- .else
- CODE sameq, "same?", FLAG_NORMAL
- ld.w %r4, [%r1] ; address 1
- xld.w %r5, [%r1 + 4] ; address 2
- ld.ub %r6, [%r4]+ ; count 1
- ld.ub %r7, [%r5]+ ; count 2
- cmp %r6, %r7 ; counts must be equal
- jrne sameq_false ; ...no
- sameq_loop:
- ld.ub %r7,[%r4]+ ; get byte from string 1
- ld.ub %r8,[%r5]+ ; get byte from string 2
- cmp %r7, %r8 ; check if equal
- jrne sameq_false ; ..not equal => false result
- sub %r6, 1 ; decrement counter
- jrne sameq_loop ; go back for more
- sub %r1, BYTES_PER_CELL
- ld.w %r4, TRUE ; matched
- ld.w [%r1], %r4 ; ..
- NEXT
- sameq_false:
- sub %r1, BYTES_PER_CELL
- ld.w %r4, FALSE ; match failed
- xld.w [%r1], %r4 ; ..
- NEXT
- END_CODE
- .endif
- ;;; : find ( a va -- ca na, a F )
- ;;; BEGIN @ DUP \ a na na
- ;;; IF \ a na
- ;;; SAME? 0= \ a na f
- ;;; ELSE \ a na
- ;;; DROP FALSE EXIT \ a F
- ;;; THEN
- ;;; WHILE NAME>LINK \ a la
- ;;; REPEAT
- ;;; \ a na
- ;;; NIP DUP NAME>CODE SWAP ;
- .if PREFER_FORTH_CODE
- COLON find, "find", FLAG_NORMAL
- find_l1:
- .long fetch, dup, qbranch, find_l2
- .long sameq, zero_equal
- .long branch, find_l3
- find_l2:
- .long drop, dolit, FALSE
- .long exit
- find_l3:
- .long qbranch, find_l4
- .long name_to_link, branch, find_l1
- find_l4:
- .long nip, dup, name_to_code, swap
- .long exit
- .else
- CODE find, "find", FLAG_NORMAL
- ld.w %r4, [%r1] ; va
- find_loop:
- ld.w %r4, [%r4]
- or %r4, %r4
- jreq find_not_found
- ;; comparison of counted strings is inlined for speed
- xld.w %r5, [%r1 + 4] ; a
- ld.w %r6, %r4
- ld.ub %r7, [%r5]+ ; count 1
- ld.ub %r8, [%r6]+ ; count 2
- cmp %r7, %r8 ; counts must be equal
- jrne find_next ; ...no
- find_cmp_loop:
- ld.ub %r8,[%r5]+ ; get 1 byte from string 1
- ld.ub %r9,[%r6]+ ; get 1 byte from string 2
- cmp %r8, %r9 ; check if equal
- jrne find_next ; ..not equal => false result
- sub %r7, 1 ; decrement counter
- jrne find_cmp_loop ; go back for more bytes
- find_found:
- ld.w [%r1], %r4 ; na
- xld.w %r5, DICTIONARY_CODE_OFFSET_BYTES
- sub %r4, %r5 ; NAME>CODE
- xld.w [%r1 + 4], %r4 ; ca
- NEXT
- find_next:
- xld.w %r5, DICTIONARY_LINK_OFFSET_BYTES
- jp.d find_loop ; try next word (delayed)
- sub %r4, %r5 ; NAME>LINK
- find_not_found:
- ld.w %r4, FALSE
- ld.w [%r1], %r4 ; F
- NEXT
- END_CODE
- .endif
- ;;; : NAME? ( a -- ca na, a F )
- ;;; CONTEXT DUP 2@ XOR IF CELL- THEN >R \ context<>also
- ;;; BEGIN R> CELL+ DUP >R @ ?DUP
- ;;; WHILE find ?DUP
- ;;; UNTIL R> DROP EXIT THEN R> DROP 0 ;
- COLON nameq, "name?", FLAG_NORMAL
- .long context, dup, dfetch, _xor
- .long qbranch, nameq_l1
- .long cell_minus
- nameq_l1:
- .long to_r
- nameq_l2:
- .long r_from, cell_plus, dup, to_r
- .long fetch, qdup
- .long qbranch, nameq_l3
- .long find, qdup
- .long qbranch, nameq_l2
- .long r_from, drop, exit
- nameq_l3:
- .long r_from, drop
- .long dolit, 0, exit
- ;;; .( Terminal )
- ;;; : ^H ( b b b -- b b b ) \ backspace
- ;;; >R OVER R@ < DUP
- ;;; IF [ CTRL H ] LITERAL 'ECHO @EXECUTE THEN R> + ;
- COLON bksp, "^h", FLAG_NORMAL
- .long to_r, over, r_from, swap, over, _xor
- .long qbranch, bksp_l1
- .long dolit, backspace, techo, atexecute, dolit, 1, minus
- .long blank, techo, atexecute
- .long dolit, backspace, techo, atexecute
- bksp_l1:
- .long exit
- ;;; : TAP ( bot eot cur key -- bot eot cur )
- ;;; DUP 'ECHO @EXECUTE OVER C! 1+ ;
- COLON tap, "tap", FLAG_NORMAL
- .long dup, techo, atexecute, over, cstore, increment, exit
- ;;; : kTAP ( bot eot cur key -- bot eot cur )
- ;;; DUP 13 XOR
- ;;; IF [ CTRL H ] LITERAL XOR IF BL TAP ELSE ^H THEN EXIT
- ;;; THEN DROP NIP DUP ;
- COLON ktap, "ktap", FLAG_NORMAL
- .long dup, dolit, carriage_return, _xor
- .long qbranch, ktap_l2
- .long dolit, delete, _xor
- .long qbranch, ktap_l1
- .long blank, tap, exit
- ktap_l1:
- .long bksp, exit
- ktap_l2:
- .long drop, swap, drop, dup, exit
- ;;; : accept ( b u -- b u2 )
- ;;; OVER + OVER
- ;;; BEGIN 2DUP XOR
- ;;; WHILE KEY DUP BL - 95 U<
- ;;; IF TAP ELSE 'TAP @EXECUTE THEN
- ;;; REPEAT DROP OVER - ;
- COLON accept, "accept", FLAG_NORMAL
- .long over, plus, over
- accept_l1:
- .long twodup, _xor, qbranch, accept_l4
- .long key, dup, blank, minus, dolit, 95, uless
- .long qbranch, accept_l2
- .long tap, branch, accept_l3
- accept_l2:
- .long ttap, atexecute
- accept_l3:
- .long branch, accept_l1
- accept_l4:
- .long drop, over, minus, exit
- ;;; : EXPECT ( b u -- ) 'EXPECT @EXECUTE SPAN ! DROP ;
- colon expect, "expect", FLAG_NORMAL
- .long texpect, atexecute, span, store, drop, exit
- ;;; : QUERY ( -- )
- ;;; TIB 256 'EXPECT @EXECUTE #TIB ! 0 NIP >IN ! ;
- COLON query, "query", FLAG_NORMAL
- .long tib, dolit, 256, texpect, atexecute, hash_tib, store
- .long drop, dolit, 0, to_in, store, exit
- ;;; .( File input - substitutes for accept above )
- ;;; CREATE SOURCE-ID 0 ,
- VARIABLE source_id, "source-id", FLAG_NORMAL
- .long 0
- ;;; : FILE-READER ( b u -- b u2 )
- ;;; OVER SWAP SOURCE-ID @ READ-LINE \ b u2 f ior
- ;;; ?DUP IF CR ." read error = " . CR \ b u2
- ;;; SOURCE-ID @ CLOSE-FILE DROP
- ;;; 2DROP HAND
- ;;; TRUE ABORT" file error"
- ;;; THEN
- ;;; IF EXIT
- ;;; ELSE SOURCE-ID @ CLOSE-FILE DROP
- ;;; FILEID-STACK STACK-POP DUP SOURCE-ID !
- ;;; 0= IF HAND THEN
- ;;; THEN
- ;;; ;
- COLON file_reader, "file-reader", FLAG_NORMAL
- .long over, swap, source_id, fetch, read_line
- .long qdup, qbranch, file_reader_l1
- .long cr, do_dot_quote
- FSTRING "read error = "
- .long dot, cr
- .long source_id, fetch, close_file, drop
- .long twodrop, hand
- .long dolit, TRUE, do_abort_quote
- FSTRING "file error"
- file_reader_l1:
- .long qbranch, file_reader_l2
- .long exit
- file_reader_l2:
- .long source_id, fetch, close_file, drop
- .long fileid_stack, stack_pop, dup, source_id, store
- .long zero_equal, qbranch, file_reader_l3
- .long hand
- file_reader_l3:
- .long exit
- ;;; .( Error handling )
- ;;; : CATCH ( ca -- err#/0 )
- ;;; SP@ >R HANDLER @ >R RP@ HANDLER !
- ;;; EXECUTE
- ;;; R> HANDLER ! R> DROP 0 ;
- COLON catch, "catch", FLAG_NORMAL
- .long sp_fetch
- .long to_r, handler, fetch, to_r
- .long rp_fetch, handler, store, execute
- .long r_from, handler, store
- .long r_from, drop, dolit, 0, exit
- ;;; : THROW ( err# -- err# )
- ;;; HANDLER @ RP! R> HANDLER ! R> SWAP >R SP! DROP R> ;
- COLON throw, "throw", FLAG_NORMAL
- .long handler, fetch, rp_store
- .long r_from, handler, store
- .long r_from, swap, to_r, sp_store
- .long drop, r_from, exit
- ;;; VARIABLE NULL$
- VARIABLE null_dollar, "null$", FLAG_NORMAL
- .long 0
- ;;; : ABORT ( -- ) NULL$ THROW ;
- COLON abort, "abort", FLAG_NORMAL
- .long null_dollar, throw, exit
- ;;; : (abort") ( f -- ) IF do$ THROW THEN do$ DROP ; COMPILE-ONLY
- COLON do_abort_quote, "(abort\042)", FLAG_COMPILE_ONLY
- .long qbranch, do_abort_quote_l1
- .long do_dollar, throw
- do_abort_quote_l1:
- .long do_dollar, drop, exit
- ;;; .( Interpret )
- ;;; : $INTERPRET ( a -- )
- ;;; NAME? ?DUP
- ;;; IF @ [ =COMP ] LITERAL AND
- ;;; ABORT" compile ONLY" EXECUTE EXIT
- ;;; THEN
- ;;; 'NUMBER @EXECUTE
- ;;; IF EXIT THEN THROW ;
- COLON dollar_interpret, "$interpret", FLAG_NORMAL
- .long nameq, qdup
- .long qbranch, dollar_interpret_l1
- .long name_to_flags, fetch, dolit, FLAG_COMPILE_ONLY, _and
- .long do_abort_quote
- FSTRING " compile only "
- .long execute
- .long exit
- dollar_interpret_l1:
- .long tnumber, atexecute
- .long qbranch, dollar_interpret_l2
- .long exit
- dollar_interpret_l2:
- .long throw
- ;;; : [ ( -- ) ['] $INTERPRET 'EVAL ! ; IMMEDIATE
- COLON left_bracket, "[", FLAG_IMMEDIATE
- .long dolit, dollar_interpret, teval, store, exit
- ;;; : .OK ( -- ) ['] $INTERPRET 'EVAL @ = IF ." ok" THEN CR ;
- COLON dot_ok, ".ok", FLAG_NORMAL
- .long dolit, dollar_interpret, teval, fetch, equal
- .long qbranch, dot_ok_l1
- .long do_dot_quote
- FSTRING " Ok"
- dot_ok_l1:
- .long cr, exit
- ;;; : ?STACK ( -- ) DEPTH 0< IF $" underflow" THROW THEN ;
- COLON qstack, "?stack", FLAG_NORMAL
- .long depth, zero_less
- .long do_abort_quote
- FSTRING " underflow"
- .long exit
- ;;; : EVAL ( -- )
- ;;; BEGIN TOKEN DUP C@
- ;;; WHILE 'EVAL @EXECUTE ?STACK
- ;;; REPEAT DROP 'PROMPT @EXECUTE ;
- COLON eval, "eval", FLAG_NORMAL
- eval_l1:
- .long token, dup, cfetch
- .long qbranch, eval_l2
- .long teval, atexecute, qstack
- .long branch, eval_l1
- eval_l2:
- .long drop, tprompt, atexecute, exit
- ;;; .( Device I/O )
- ;;; CODE IO? ( -- f ) \ FFFF is an impossible character
- ;;; XOR BX, BX
- ;;; MOV DL, # $0FF \ input
- ;;; MOV AH, # 6 \ MS-DOS Direct Console I/O
- ;;; INT $021
- ;;; 0<> IF \ ?key ready
- ;;; OR AL, AL
- ;;; 0= IF \ ?extended ascii code
- ;;; INT $021
- ;;; MOV BH, AL \ extended code in msb
- ;;; ELSE MOV BL, AL
- ;;; THEN
- ;;; PUSH BX
- ;;; MOVE BX, # -1
- ;;; THEN
- ;;; PUSH BX
- ;;; NEXT
- ;;; END-CODE
- ;;; input character
- CODE rx_query, "rx?", FLAG_NORMAL ; ( -- c T | F )
- xcall Serial_InputAvailable
- or %r4, %r4
- jreq rx_query_no_character
- xcall Serial_GetChar
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- ld.w %r4, TRUE
- rx_query_no_character:
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; output a character
- CODE tx_store, "tx!", FLAG_NORMAL ; ( c -- )
- ld.w %r6, [%r1]+
- xcall Serial_PutChar
- NEXT
- END_CODE
- ;;; : !IO ( -- ) ; IMMEDIATE \ initialize I/O device
- ;;; *missing*
- ;;; .( Shell )
- ;;; : PRESET ( -- ) SP0 @ SP! [ =TIB ] LITERAL #TIB CELL+ !
- ;;; FILESYSTEM-CLOSE-ALL FILEID-STACK STACK-CLEAR
- ;;; 0 SOURCE-ID ! ;
- COLON preset, "preset", FLAG_NORMAL
- .long sp0, fetch, sp_store
- .long dolit, terminal_buffer, hash_tib, cell_plus, store
- .long filesystem_close_all
- .long fileid_stack, stack_clear
- .long dolit, 0, source_id, store
- .long exit
- ;;; : XIO ( a a a a -- ) \ reset 'TAP 'ECHO 'PROMPT 'EXPECT
- ;;; ['] accept 'EXPECT ! 'TAP ! 'ECHO ! 'PROMPT ! ;
- COLON xio, "xio", FLAG_NORMAL
- .long ttap, store
- .long techo, store
- .long tprompt, store
- .long texpect, store
- .long exit
- ;;; \ first cell stack size
- ;;; \ second cell is the index
- ;;; 20 DUP CREATE FILEID-STACK 2 + CELLS ALLOT
- ;;; FILEID-STACK !
- fileid_stack_length = 20
- VARIABLE fileid_stack, "fileid-stack", FLAG_NORMAL
- .long fileid_stack_length ; size
- .long 0 ; index
- ;; there must be the 'size' field above
- .rept fileid_stack_length
- .long 0
- .endr
- ;;; : INCLUDE-FILE ( fileid -- )
- ;;; SOURCE-ID @ FILEID-STACK STACK-PUSH
- ;;; SOURCE-ID !
- ;;; ['] FILE-READER ['] PACE ['] DROP ['] kTAP XIO ;
- COLON include_file, "include-file", FLAG_NORMAL
- .long source_id, fetch, fileid_stack, stack_push
- .long source_id, store
- .long dolit, file_reader, dolit, 0, dolit, drop, dolit, ktap, xio, exit
- ;;; : INCLUDED ( b u -- )
- ;;; R/O OPEN-FILE \ fileid ior
- ;;; ?DUP IF CR ." open error = " . DROP
- ;;; ELSE CR INCLUDE-FILE
- ;;; THEN ;
- COLON included, "included", FLAG_NORMAL
- .long readonly, open_file
- .long qdup, qbranch, include_quote_l1
- .long cr, do_dot_quote
- FSTRING "open error = "
- .long dot, drop, exit
- include_quote_l1:
- .long hash_tib, fetch, to_in, store ; empty the buffer
- .long cr, include_file, exit
- ;;; : INCLUDE" ( -- \ <string>" )
- ;;; [CHAR] " PARSE INCLUDED ;
- COLON include_quote, "include\042", FLAG_NORMAL
- .long dolit, '\"', parse, included, exit
- ;;; : INCLUDE ( -- \ <string> )
- ;;; BL PARSE INCLUDED ;
- COLON include, "include", FLAG_NORMAL
- .long blank, parse, included, exit
- ;;; : HAND ( -- )
- ;;; ['] accept ['] .OK 'EMIT @ ['] kTAP XIO ;
- COLON hand, "hand", FLAG_NORMAL
- .long dolit, accept, dolit, dot_ok, temit, fetch, dolit, ktap, xio
- .long hash_tib, fetch, to_in, store ; empty the buffer
- .long exit
- ;;; CREATE I/O ' ?RX , ' TX! , \ defaults
- ;;; ** Missing **
- ;;; : CONSOLE ( -- ) I/O 2@ 'KEY? 2! HAND ;
- COLON console, "console", FLAG_NORMAL
- .long dolit, rx_query, tkey_query, store
- .long dolit, tx_store, temit, store
- .long hand, exit
- ;;; : que ( -- ) QUERY EVAL ;
- ; COLON que, "que", FLAG_NORMAL
- ; .long query, eval, exit
- ;;; : QUIT ( -- ) \ clear return stack ONLY
- ;;; RP0 @ RP!
- ;;; BEGIN [COMPILE] [
- ;;; BEGIN ['] que CATCH ?DUP
- ;;; UNTIL ( a)
- ;;; CONSOLE NULL$ OVER XOR
- ;;; IF CR TIB #TIB @ TYPE
- ;;; CR >IN @ [CHAR] ^ CHARS
- ;;; CR .$ ." ? "
- ;;; THEN PRESET
- ;;; AGAIN ;
- COLON quit, "quit", FLAG_NORMAL
- .long rp0, fetch, rp_store
- quit_l1:
- .long left_bracket
- quit_l2:
- .long query
- .long dolit, eval, catch
- .long qdup
- .long qbranch, quit_l2
- .long tprompt, fetch, to_r
- .long console, null_dollar, over, _xor
- .long qbranch, quit_l3
- .long space, count, type
- .long do_dot_quote
- FSTRING " ? "
- quit_l3:
- .long r_from, dolit, dot_ok, _xor
- .long qbranch, quit_l4
- .long dolit, '?', emit
- quit_l4:
- .long preset
- .long branch, quit_l1
- ;;; .( Compiler Primitives )
- ;;; : ' ( -- ca \ <string> ) TOKEN NAME? IF EXIT THEN THROW ;
- COLON tick, "'", FLAG_NORMAL
- .long token, nameq
- .long qbranch, tick_l1
- .long exit
- tick_l1:
- .long throw, exit
- ;;; : ['] ( -- \ <string> ) ' LITERAL ; IMMEDIATE COMPILE_ONLY
- ;;; \ runtime ( -- ca )
- COLON bracket_tick, "[']", FLAG_IMMEDIATE + FLAG_COMPILE_ONLY
- .long tick, literal, exit
- ;;; : ALLOT ( n -- ) CP +! ;
- COLON allot, "allot", FLAG_NORMAL
- .long cp, plus_store, exit
- ;;; : , ( w -- ) HERE ALIGNED DUP CELL+ CP ! ! ;
- COLON comma, ",", FLAG_NORMAL
- .long here, aligned, dup, cell_plus, cp
- .long store, store, exit
- ;;; : c, ( w -- ) HERE DUP CHAR+ CP ! C! ;
- COLON c_comma, "c,", FLAG_NORMAL
- .long here, dup, char_plus, cp
- .long store, cstore, exit
- ;;; : [COMPILE] ( -- \ <string> ) ' , ; IMMEDIATE
- COLON bracket_compile, "[compile]", FLAG_IMMEDIATE
- .long tick, comma, exit
- ;;; : COMPILE ( -- ) R> DUP @ , CELL+ >R ; COMPILE-ONLY
- COLON compile, "compile", FLAG_COMPILE_ONLY
- .long r_from, dup, fetch, comma, cell_plus, to_r, exit
- ;;; : LITERAL ( w -- ) COMPILE (dolit) , ; IMMEDIATE
- COLON literal, "literal", FLAG_IMMEDIATE
- .long compile, dolit, comma, exit
- ;;; : $," ( -- \ <string>" ) [CHAR] " PARSE HERE PACK$ C@ 1+ ALLOT ;
- COLON dollar_comma_quote, "$,\042", FLAG_NORMAL
- .long dolit, '\"', parse, here, pack_dollar, cfetch, increment, allot, exit
- ;;; : RECURSE ( -- ) LAST @ CURRENT @ ! ; IMMEDIATE
- COLON recurse, "recurse", FLAG_IMMEDIATE
- .long last, fetch, current, fetch, store, exit
- ;;; .( Structures )
- ;;; : FOR ( -- a ) COMPILE >R HERE ; IMMEDIATE
- COLON for, "for", FLAG_IMMEDIATE
- .long compile, to_r, here, exit
- ;;; : BEGIN ( -- a ) HERE ; IMMEDIATE
- COLON begin, "begin", FLAG_IMMEDIATE
- .long here, exit
- ;;; : NEXT ( a -- ) COMPILE (next) , ; IMMEDIATE
- COLON next, "next", FLAG_IMMEDIATE
- .long compile, donext, comma, exit
- ;;; : UNTIL ( a -- ) COMPILE ?branch , ; IMMEDIATE
- COLON until, "until", FLAG_IMMEDIATE
- .long compile, qbranch, comma, exit
- ;;; : AGAIN ( a -- ) COMPILE branch , ; IMMEDIATE
- COLON again, "again", FLAG_IMMEDIATE
- .long compile, branch, comma, exit
- ;;; : IF ( -- A ) COMPILE ?branch HERE 0 , ; IMMEDIATE
- COLON if, "if", FLAG_IMMEDIATE
- .long compile, qbranch, here, dolit, 0, comma, exit
- ;;; : AHEAD ( -- A ) COMPILE branch HERE 0 , ; IMMEDIATE
- COLON ahead, "ahead", FLAG_IMMEDIATE
- .long compile, branch, here, dolit, 0, comma, exit
- ;;; : REPEAT ( A a -- ) [COMPILE] AGAIN HERE SWAP ! ; IMMEDIATE
- COLON repeat, "repeat", FLAG_IMMEDIATE
- .long again, here, swap, store, exit
- ;;; : THEN ( A -- ) HERE SWAP ! ; IMMEDIATE
- COLON then, "then", FLAG_IMMEDIATE
- .long here, swap, store, exit
- ;;; : AFT ( a -- a A ) DROP [COMPILE] AHEAD [COMPILE] BEGIN SWAP ; IMMEDIATE
- COLON aft, "aft", FLAG_IMMEDIATE
- .long drop, ahead, begin, swap, exit
- ;;; : ELSE ( A -- A ) [COMPILE] AHEAD SWAP [COMPILE] THEN ; IMMEDIATE
- COLON else, "else", FLAG_IMMEDIATE
- .long ahead, swap, then, exit
- ;;; : WHILE ( a -- A a ) [COMPILE] IF SWAP ; IMMEDIATE
- COLON while, "while", FLAG_IMMEDIATE,
- .long if, swap, exit
- ;;; : ABORT" ( -- \ <string> ) COMPILE (abort") $," ; IMMEDIATE
- COLON abortquote, "abort\042", FLAG_IMMEDIATE
- .long compile, do_abort_quote, dollar_comma_quote, exit
- ;;; : $" ( -- \ <string>" ) COMPILE ($") $," ; IMMEDIATE
- COLON dollar_quote, "$\042", FLAG_IMMEDIATE
- .long compile, do_dollar_quote, dollar_comma_quote, exit
- ;;; : ." ( -- \ <string>" ) COMPILE ."| $," ; IMMEDIATE
- COLON dot_quote, ".\042", FLAG_IMMEDIATE
- .long compile, do_dot_quote, dollar_comma_quote, exit
- ;;; .( Name Compiler )
- ;;; : ?UNIQUE ( a -- a )
- ;;; DUP NAME? IF ." redefined " OVER .$ THEN DROP ;
- COLON qunique, "?unique", FLAG_NORMAL
- .long dup, nameq
- .long qbranch, qunique_l1
- .long do_dot_quote
- FSTRING " redefined "
- .long over, dot_dollar
- qunique_l1:
- .long drop, exit
- ;;; \ assumes the name is in the right place and the header
- ;;; \ has already be reserved (TOKEN does this)
- ;;; : $,n ( na -- )
- ;;; DUP C@
- ;;; IF ?UNIQUE
- ;;; ( na ) DUP LAST ! \ for OVERT
- ;;; ( na ) HERE ALIGNED SWAP
- ;;; ( cp na ) DUP NAME>LINK
- ;;; ( cp na la) CURRENT @ @ \ previous name
- ;;; ( cp na la na') SWAP !
- ;;; ( cp na ) DUP COUNT + ALIGNED NP !
- ;;; ( cp na ) NAME>PARAM ! EXIT
- ;;; THEN $" name" THROW ;
- COLON dollar_comma_n, "$,n", FLAG_NORMAL
- .long dup, cfetch ; cfetch for string count (strlen ??)
- .long qbranch, dollar_comma_n_l1
- .long qunique
- .long dup, last, store
- .long here, aligned, swap
- .long dup, name_to_link
- .long current, fetch, fetch
- .long swap, store
- .long dup
- .long count, plus, aligned ; skip over the name
- .long np, store
- .long name_to_param
- .long store
- .long exit
- dollar_comma_n_l1:
- .long do_dollar_quote
- FSTRING "name"
- .long throw
- ;;; .( FORTH Compiler )
- ;;; : $COMPILE ( a -- )
- ;;; NAME? ?DUP
- ;;; IF NAME>FLAGS @ [ =FLAG-IMMEDIATE ] LITERAL AND
- ;;; IF EXECUTE ELSE , THEN EXIT
- ;;; THEN
- ;;; 'NUMBER @EXECUTE
- ;;; IF [COMPILE] LITERAL EXIT
- ;;; THEN THROW ;
- colon dollar_compile, "$compile", FLAG_NORMAL
- .long nameq, qdup
- .long qbranch, dollar_compile_l2
- .long name_to_flags, fetch, dolit, FLAG_IMMEDIATE, _and
- .long qbranch, dollar_compile_l1
- .long execute, exit
- dollar_compile_l1:
- .long comma, exit
- dollar_compile_l2:
- .long tnumber, atexecute
- .long qbranch, dollar_compile_l3
- .long literal, exit
- dollar_compile_l3:
- .long throw
- ;;; : OVERT ( -- ) LAST @ CURRENT @ ! ;
- COLON overt, "overt", FLAG_NORMAL
- .long last, fetch, current, fetch, store, exit
- ;;; : ; ( -- )
- ;;; COMPILE EXIT [COMPILE] [ OVERT ; COMPILE-ONLY IMMEDIATE
- COLON semicolon, "\073", FLAG_COMPILE_ONLY + FLAG_IMMEDIATE
- .long compile, exit
- .long left_bracket, overt, exit
- ;;; : ] ( -- ) ['] $COMPILE 'EVAL ! ;
- COLON right_bracket, "]", FLAG_NORMAL
- .long dolit, dollar_compile, teval, store, exit
- ;;; \ basic defining word call like: ' (doXXX) (DEFINE) THING
- ;;; \ and it will place the address of the actual code for (doXXX)
- ;;; \ into the code pointer for thing
- ;;; : (DEFINE) ( code -- \ <string> ) TOKEN DUP $,n
- ;;; SWAP OVER NAME>CODE !
- ;;; [ =FLAG-NORMAL ] LITERAL SWAP NAME>FLAGS ! ;
- COLON paren_define, "(define)", FLAG_NORMAL
- .long token, dup, dollar_comma_n
- .long swap, over, name_to_code, store
- .long dolit, FLAG_NORMAL, swap, name_to_flags, store
- .long exit
- ;;; : : ( -- \ <string> ) [ ' (docolon) @ ] (DEFINE) ] ;
- COLON colon, ":", FLAG_NORMAL
- .long dolit, param_docolon, paren_define
- .long right_bracket, exit
- ;;; : IMMEDIATE ( -- )
- ;;; LAST @ NAME>FLAGS DUP @
- ;;; [ =FLAG-IMMEDIATE ] LITERAL OR SWAP ! ;
- COLON _immediate, "immediate", FLAG_NORMAL
- .long last, fetch, name_to_flags, dup, fetch
- .long dolit, FLAG_IMMEDIATE, _or, swap, store, exit
- ;;; : COMPILE-ONLY ( -- )
- ;;; LAST @ NAME>FLAGS DUP @
- ;;; [ =FLAG-COMPILE-ONLY ] LITERAL OR SWAP ! ;
- COLON _compile_only, "compile-only", FLAG_NORMAL
- .long last, fetch, name_to_flags, dup, fetch
- .long dolit, FLAG_COMPILE_ONLY, _or, swap, store, exit
- ;;; .( Defining Words )
- ;;; : USER ( -- \ <string> ) [ ' (douser) @ ] LITERAL (DEFINE) OVERT ;
- COLON user, "user", FLAG_NORMAL
- .long dolit, param_douser, paren_define, overt, exit
- ;;; : CREATE ( -- \ <string> ) [ ' (dovar) @ ] LITERAL (DEFINE) OVERT ;
- COLON create, "create", FLAG_NORMAL
- .long dolit, param_dovar, paren_define, overt, exit
- ;;; : VARIABLE ( -- \ <string> ) CREATE 0 , ;
- COLON variable, "variable", FLAG_NORMAL
- .long create, dolit, 0, comma, exit
- ;;; : CONSTANT ( u -- \ <string> ) [ ' (doconst) @ ] LITERAL (DEFINE) OVERT ;
- COLON constant, "constant", FLAG_NORMAL
- .long dolit, param_doconst, paren_define, comma, overt, exit
- ;;; .( special constants )
- CONSTANT true, "true", FLAG_NORMAL
- .long TRUE
- CONSTANT false, "false", FLAG_NORMAL
- .long FALSE
- ;;; .( Tools )
- ;;; : (dump_ascii) ( b u -- ) FOR AFT COUNT >CHAR EMIT THEN NEXT DROP ;
- COLON dump_ascii,"(dump_ascii)", FLAG_NORMAL
- .long to_r
- .long branch, dump_ascii_l2
- dump_ascii_l1:
- .long count, to_char, emit
- dump_ascii_l2:
- .long donext, dump_ascii_l1
- .long drop, exit
- ;;; : (dump) ( b u -- b )
- ;;; OVER 4 U.R SPACE FOR AFT COUNT 3 U.R THEN NEXT ;
- COLON paren_dump, "(dump)", FLAG_NORMAL
- .long over, dolit, 8, u_dot_r, space
- .long to_r
- .long branch, paren_dump_l2
- paren_dump_l1:
- .long count, dolit, 3, u_dot_r
- paren_dump_l2:
- .long donext, paren_dump_l1
- .long exit
- ;;; : DUMP ( b u -- )
- ;;; BASE @ >R HEX 16 /
- ;;; FOR CR 16 2DUP (dump) -ROT 2 SPACES _TYPE ENOUGH? 0= WHILE
- ;;; NEXT ELSE R> DROP THEN DROP R> BASE ! ;
- COLON dump, "dump", FLAG_NORMAL
- .long base, fetch, to_r, hex, dolit, 16, divide
- .long to_r
- dump_l1:
- .long cr, dolit, 16, twodup, paren_dump, minus_rot, dolit, 2, spaces, dump_ascii
- .long enoughq, zero_equal, qbranch, dump_l2
- .long donext, dump_l1
- .long branch, dump_l3
- dump_l2:
- .long r_from, drop
- dump_l3:
- .long drop, r_from, base, store, exit
- ;;; : .S ( -- ) CR DEPTH FOR AFT R@ PICK . THEN NEXT ." <tos" ;
- COLON dot_s, ".s", FLAG_NORMAL
- .long cr, depth, to_r
- .long branch, dot_s_l2
- dot_s_l1:
- .long r_fetch, pick, dot
- dot_s_l2:
- .long donext, dot_s_l1
- .long do_dot_quote
- FSTRING " <tos"
- .long exit
- ;;; : !CSP ( -- ) SP@ CSP ! ;
- ;;; ** Missing **
- ;;; : ?CSP ( -- ) SP@ CSP @ XOR ABORT" stack depth" ;
- ;;; ** Missing **
- ;;; \ search to see if an unknown address is really forth code
- ;;; : CODE? ( ca -- na | F )
- ;;; CURRENT
- ;;; BEGIN CELL+ @ ?DUP WHILE 2DUP
- ;;; BEGIN @ DUP WHILE 2DUP NAME>CODE XOR
- ;;; WHILE NAME>LINK
- ;;; REPEAT THEN NIP ?DUP
- ;;; UNTIL NIP NIP EXIT THEN DROP FALSE ;
- ;;; hacked version - the vocabulary structure is not workable yet
- COLON code_query, "code?", FLAG_NORMAL
- .long current
- ;code_query_l1:
- .long cell_plus, fetch, qdup
- .long qbranch, code_query_l4
- .long twodup
- code_query_l2:
- .long fetch, dup
- .long qbranch, code_query_l3
- .long twodup, name_to_code, _xor
- .long qbranch, code_query_l3
- .long name_to_link
- .long branch, code_query_l2
- code_query_l3:
- .long nip, qdup
- ;.long qbranch, code_query_l1
- .long qbranch, code_query_l5
- .long nip, nip, exit
- code_query_l4:
- .long drop, dolit, FALSE, exit
- code_query_l5:
- .long twodrop, dolit, FALSE, exit
- ;;; disassembler for colon definitions
- ;;; does no know how to stop - press enter twice to stop
- ;;; SEE ( -- ) \ token
- ;;; BASE @
- ;;; ' CODE>NAME NAME>PARAM DUP
- ;;; CR [CHAR] $ EMIT HEX 1 U.R [ CHAR : ] EMIT
- ;;; @ CR ALIGNED CELL-
- ;;; BEGIN
- ;;; CELL+ DUP @ DUP IF CODE? THEN
- ;;; ?DUP
- ;;; IF SPACE .ID
- ;;; ELSE DUP @ DUP DECIMAL U.
- ;;; [CHAR] / EMIT
- ;;; [CHAR] $ EMIT
- ;;; HEX 1 U.R \ number
- ;;; THEN
- ;;; ENOUGH? UNTIL DROP BASE !;
- COLON see, "see", FLAG_NORMAL
- .long base, fetch
- .long tick, code_to_name, name_to_param, dup
- .long cr
- .long dolit, '$', emit
- .long hex, dolit, 1, u_dot_r
- .long dolit, ':', emit
- .long fetch
- .long cr, aligned, cell_minus
- see_l1:
- .long cell_plus, dup, fetch, dup
- .long qbranch, see_l2
- .long code_query
- see_l2:
- .long qdup
- .long qbranch, see_l3
- .long space, dot_id
- .long branch, see_l4
- see_l3:
- .long dup, fetch, dup, decimal, u_dot
- .long dolit, '/', emit, dolit, '$', emit
- .long hex, dolit, 1, u_dot_r, cr
- see_l4:
- .long enoughq, qbranch, see_l1
- .long drop, base, store, exit
- ;;; : .ID ( na -- )
- ;;; ?DUP IF COUNT $001F AND TYPE EXIT THEN ." {noName}" ;
- COLON dot_id, ".id", FLAG_NORMAL
- .long qdup, qbranch, dot_id_l1
- .long count, type, exit
- dot_id_l1:
- .long do_dot_quote
- FSTRING "{no-name}"
- .long exit
- ;;; : WORDS ( -- )
- ;;; CR CONTEXT @
- ;;; BEGIN @ ?DUP
- ;;; WHILE DUP SPACE .ID NAME>LINK ENOUGH?
- ;;; UNTIL DROP THEN ;
- COLON words, "words", FLAG_NORMAL
- .long cr, context, fetch
- words_l1:
- .long fetch, qdup
- .long qbranch, words_l2
- .long dup, space, dot_id, name_to_link
- .long enoughq, qbranch, words_l1
- .long drop
- words_l2:
- .long exit
- ;;; .( File I/O )
- ;;; : R/O ( -- fam )
- CODE readonly, "r/o", FLAG_NORMAL
- xcall FileSystem_ReadOnly
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : W/O ( -- fam )
- CODE writeonly, "w/o", FLAG_NORMAL
- xcall FileSystem_WriteOnly
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : R/W ( -- fam )
- CODE readwrite, "r/w", FLAG_NORMAL
- xcall FileSystem_ReadWrite
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r4
- NEXT
- END_CODE
- ;;; : BIN ( fam -- fam2 )
- CODE bin, "bin", FLAG_NORMAL
- ld.w %r6, [%r1] ; fam
- xcall FileSystem_bin
- ld.w [%r1], %r4 ; fam2
- NEXT
- END_CODE
- ;;; : S" ( -- \ <string> ) [COMPILE] $" COMPILE COUNT ; IMMEDIATE
- ;;; \ runtime ( -- b u )
- COLON s_quote, "s\042", FLAG_IMMEDIATE
- .long dollar_quote, compile, count, exit
- ;;; : DELETE-FILE ( b u -- ior )
- CODE delete_file, "delete-file", FLAG_NORMAL
- ld.w %r7, [%r1]+ ; count
- ld.w %r6, [%r1] ; string
- xcall FileSystem_delete
- ld.w [%r1], %r5 ; ior
- NEXT
- END_CODE
- ;;; : RENAME-FILE ( b1 u1 b2 u2 -- ior )
- CODE rename_file, "rename-file", FLAG_NORMAL
- ld.w %r9, [%r1]+ ; count2
- ld.w %r8, [%r1]+ ; name2
- ld.w %r7, [%r1]+ ; count1
- ld.w %r6, [%r1] ; name1
- xcall FileSystem_rename
- ld.w [%r1], %r5 ; ior
- NEXT
- END_CODE
- ;;; : CREATE-FILE ( b u fam -- fileid ior )
- CODE create_file, "create-file", FLAG_NORMAL
- ld.w %r8, [%r1]+ ; fam
- ld.w %r7, [%r1] ; count
- xld.w %r6, [%r1 + 4] ; string
- xcall FileSystem_create
- ld.w [%r1], %r5 ; ior
- xld.w [%r1 + 4], %r4 ; fd
- NEXT
- END_CODE
- ;;; : OPEN-FILE ( b u fam -- fileid ior )
- CODE open_file, "open-file", FLAG_NORMAL
- ld.w %r8, [%r1]+ ; fam
- ld.w %r7, [%r1] ; count
- xld.w %r6, [%r1 + 4] ; string
- xcall FileSystem_open
- ld.w [%r1], %r5 ; ior
- xld.w [%r1 + 4], %r4 ; fd
- NEXT
- END_CODE
- ;;; : CLOSE-FILE ( fileid -- ior )
- CODE close_file, "close-file", FLAG_NORMAL
- ld.w %r6, [%r1] ; fileid
- xcall FileSystem_close
- ld.w [%r1], %r5 ; ior
- NEXT
- END_CODE
- ;;; : READ-FILE ( b u fileid -- u2 ior )
- CODE read_file, "read-file", FLAG_NORMAL
- ld.w %r6, [%r1]+ ; fileid
- ld.w %r8, [%r1] ; count
- xld.w %r7, [%r1 + 4] ; buffer
- xcall FileSystem_read
- ld.w [%r1], %r5 ; ior
- xld.w [%r1 + 4], %r4 ; count2
- NEXT
- END_CODE
- ;;; : READ-LINE ( b u fileid -- u2 f ior )
- ;;; \ EOF: 0 T 0
- ;;; >R >R DUP R> R> SWAP \ b0 b fileid u
- ;;; FOR AFT \ b0 b fileid
- ;;; BEGIN
- ;;; 2DUP 1 SWAP READ-FILE \ b0 b fileid 0/1 ior
- ;;; ?DUP IF >R 2DROP SWAP - R> R> DROP EXIT THEN
- ;;; 0= IF DROP SWAP - DUP 0 R> DROP EXIT THEN \ u2 f 0
- ;;; \ b0 b fileid
- ;;; OVER C@ [CTRL] M XOR \ b0 b fileid f
- ;;; UNTIL
- ;;; \ here have a non CR character
- ;;; OVER C@ [CTRL] J = IF DROP SWAP - TRUE 0 R> DROP EXIT THEN
- ;;; >R 1+ R> \ b0 b+1 fileid
- ;;; THEN NEXT
- ;;; \ filled buffer without CR/LF \ b0 b' fileid
- ;;; DROP SWAP - TRUE 0 \ u2 T 0
- ;;; ;
- COLON read_line, "read-line", FLAG_NORMAL
- .long to_r, to_r, dup, r_from, r_from, swap
- .long to_r
- .long branch, read_line_l5
- read_line_l1:
- .long twodup, dolit, 1, swap, read_file
- .long qdup, qbranch, read_line_l2
- .long to_r, twodrop, swap, minus, true, r_from, r_from, drop, exit
- read_line_l2:
- .long zero_equal, qbranch, read_line_l3
- .long drop, swap, minus, dup, dolit, 0, r_from, drop, exit
- read_line_l3:
- .long over, cfetch, dolit, 13, _xor, qbranch, read_line_l1
- .long over, cfetch, dolit, 10, equal, qbranch, read_line_l4
- .long drop, swap, minus, true, dolit, 0, r_from, drop, exit
- read_line_l4:
- .long to_r, increment, r_from
- read_line_l5:
- .long donext, read_line_l1
- .long drop, swap, minus, true, dolit, 0, exit
- ;;; : WRITE-FILE ( b u fileid -- u2 ior )
- CODE write_file, "write-file", FLAG_NORMAL
- ld.w %r6, [%r1]+ ; fileid
- ld.w %r8, [%r1] ; count
- xld.w %r7, [%r1 + 4] ; buffer
- xcall FileSystem_write
- ld.w [%r1], %r5 ; ior
- xld.w [%r1 + 4], %r4 ; count2
- NEXT
- END_CODE
- ;;; : FLUSH-FILE ( fileid -- ior )
- CODE flush_file, "flush-file", FLAG_NORMAL
- ld.w %r6, [%r1] ; fileid
- xcall FileSystem_sync
- ld.w [%r1], %r5 ; ior
- NEXT
- END_CODE
- ;;; : FILE-SIZE ( fileid -- u ior )
- CODE file_size, "file-size", FLAG_NORMAL
- ld.w %r6, [%r1] ; fileid
- xcall FileSystem_lsize
- ld.w [%r1], %r4 ; size
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r5 ; ior
- NEXT
- END_CODE
- ;;; : FILE-POSITION ( fileid -- u ior )
- CODE file_position, "file-position", FLAG_NORMAL
- ld.w %r6, [%r1] ; fileid
- xcall FileSystem_ltell
- ld.w [%r1], %r4 ; pos
- sub %r1, BYTES_PER_CELL
- ld.w [%r1], %r5 ; ior
- NEXT
- END_CODE
- ;;; : REPOSITION-FILE ( u fileid -- ior )
- CODE reposition_file, "reposition-file", FLAG_NORMAL
- ld.w %r6, [%r1]+ ; fileid
- ld.w %r7, [%r1] ; pos
- xcall FileSystem_lseek
- ld.w [%r1], %r5 ; ior
- NEXT
- END_CODE
- ;;; : FILESYSTEM-INIT ( -- )
- CODE filesystem_init, "filesystem-init", FLAG_NORMAL
- xcall FileSystem_initialise
- NEXT
- END_CODE
- ;;; : FILESYSTEM-CLOSE-ALL ( -- )
- CODE filesystem_close_all, "filesystem-close-all", FLAG_NORMAL
- xcall FileSystem_CloseAll
- NEXT
- END_CODE
- ;;; : OPEN-DIRECTORY ( b u -- dirid ior )
- CODE open_directory, "open-directory", FLAG_NORMAL
- ld.w %r7, [%r1] ; count
- xld.w %r6, [%r1 + 4] ; buffer
- xcall FileSystem_OpenDirectory
- ld.w [%r1], %r5 ; ior
- xld.w [%r1 + 4], %r4 ; count2
- NEXT
- END_CODE
- ;;; : CLOSE-DIRECTORY ( dirid -- ior )
- CODE close_directory, "close-directory", FLAG_NORMAL
- ld.w %r6, [%r1] ; dirid
- xcall FileSystem_CloseDirectory
- ld.w [%r1], %r5 ; ior
- NEXT
- END_CODE
- ;;; : READ-DIRECTORY ( b u dirid -- u2 ior )
- CODE read_directory, "read-directory", FLAG_NORMAL
- ld.w %r6, [%r1]+ ; dirid
- ld.w %r8, [%r1] ; count
- xld.w %r7, [%r1 + 4] ; buffer
- xcall FileSystem_ReadDirectory
- ld.w [%r1], %r5 ; ior
- xld.w [%r1 + 4], %r4 ; count2
- NEXT
- END_CODE
- ;;; .( Access to low level sectors on disk )
- ;;; \ buffer size = count * 512 bytes
- ;;; : READ-SECTORS ( b count sector -- ior )
- CODE read_sectors, "read-sectors", FLAG_NORMAL
- ld.w %r6, [%r1]+ ; sector
- ld.w %r8, [%r1]+ ; count
- xld.w %r7, [%r1] ; buffer
- xcall FileSystem_AbsoluteRead
- ld.w [%r1], %r5 ; ior
- NEXT
- END_CODE
- ;;; \ buffer size = count * 512 bytes
- ;;; : WRITE-SECTORS ( b count sector -- ior )
- CODE write_sectors, "write-sectors", FLAG_NORMAL
- ld.w %r6, [%r1]+ ; sector
- ld.w %r8, [%r1]+ ; count
- xld.w %r7, [%r1] ; buffer
- xcall FileSystem_AbsoluteWrite
- ld.w [%r1], %r5 ; ior
- NEXT
- END_CODE
- ;;; .( Hardware reset )
- ;;; \ version
- ;;; =BUILD-NUMBER CONSTANT BUILD ( -- u )
- CONSTANT build, "build", FLAG_NORMAL
- .long BUILD_NUMBER
- ;;; BANNER ( -- ) CR <message> CR
- COLON banner, "banner", FLAG_NORMAL
- .long cr
- .long do_dot_quote
- FSTRING "S33 forth interpreter (build:"
- .long build, u_dot, do_dot_quote
- FSTRING ")"
- .long cr, exit
- ;;; CREATE 'BOOT ' BANNER , \ application vector
- VARIABLE tboot, "'boot", FLAG_NORMAL
- .long banner
- ;;; MACRO INIT-USER-VARIABLES
- .macro INIT_USER_VARIABLES
- .long dolit, initial_stack_pointer, sp0, store
- .long dolit, initial_return_pointer, rp0, store
- .long dolit, rx_query, tkey_query, store
- .long dolit, tx_store, temit, store
- .long dolit, accept, texpect, store
- .long dolit, ktap, ttap, store
- .long dolit, tx_store, techo, store
- .long dolit, dot_ok, tprompt, store
- .long dolit, 10, base, store
- .long dolit, 0, temp, store
- .long dolit, 0, span, store
- .long dolit, 0, to_in, store
- .long dolit, 0, hash_tib, store
- .long dolit, terminal_buffer, hash_tib, cell_plus, store
- .long dolit, dollar_interpret, teval, store
- .long dolit, numberq, tnumber, store
- .long dolit, 0, hld, store
- .long dolit, 0, handler, store
- .long dolit, 0, context, store
- .long dolit, 0, context, dolit, 1, cells, plus, store
- .long dolit, 0, context, dolit, 2, cells, plus, store
- .long dolit, 0, context, dolit, 3, cells, plus, store
- .long dolit, 0, context, dolit, 4, cells, plus, store
- .long dolit, 0, context, dolit, 5, cells, plus, store
- .long dolit, 0, context, dolit, 6, cells, plus, store
- .long dolit, 0, context, dolit, 7, cells, plus, store
- .long dolit, 0, context, dolit, 8, cells, plus, store
- .long dolit, 0, current, store
- .long dolit, 0, current, cell_plus, store
- .long dolit, end_of_code, cp, store
- .long dolit, end_of_dictionary, cp, cell_plus, store
- .long dolit, last_name, cp, cell_plus, cell_plus, store
- .endm
- ;;; : COLD ( -- )
- ;;; \ init CPU
- ;;; \ init stacks
- ;;; \ init user area
- ;;; \ init IP
- ;;; PRESET
- ;;; FORTH CONTEXT @ DUP CURRENT D! OVERT
- ;;; 'BOOT @EXECUTE
- ;;; QUIT ;
- COLON cold, "cold", FLAG_NORMAL
- INIT_USER_VARIABLES
- .long preset, filesystem_init
- .long forth, context, fetch, dup, current, dstore, overt
- .long tboot, atexecute
- .long do_dollar_quote
- FSTRING "forth.4th"
- .long count, included
- .long do_dollar_quote
- FSTRING "auto.4th"
- .long count, readonly, open_file
- .long qbranch, have_auto
- .long drop, branch, run_quit
- have_auto:
- .long include_file
- run_quit:
- .long quit
- COLON nop, "nop", FLAG_NORMAL ;debug
- .long exit
- CODE BREAKPOINT, "(brk)", FLAG_NORMAL ;debug
- xcall xdebug ;debug
- xld.w %r6, bpt
- xcall Serial_PutString
- s1: jp s1 ;debug
- bpt: .asciz "STOPPED\r\n"
- .balign 4
- CODE DEBUG, "(debug)", FLAG_NORMAL ;debug
- xcall xdebug ;debug
- NEXT ;debug
- END_CODE ;debug
- ;;; delay in micro seconds
- CODE delay_micro_seconds, "delay-us", FLAG_NORMAL
- ld.w %r5, [%r1]+
- delay_micro_seconds_outer:
- ld.w %r4, 12
- delay_micro_seconds_loop:
- nop
- sub %r4, 1
- jrne delay_micro_seconds_loop
- sub %r5, 1
- jrne delay_micro_seconds_outer
- NEXT
- END_CODE
- ;;; finish off the dictionary
- .section .forth_dict
- .balign 4
- end_of_dictionary:
- .long 0,0
- .space 65536 ; space for more names
- end_of_dictionary_memory:
- last_name = __last_name ; should be the final name
- ;;; finish off the code
- .section .forth_param
- .balign 4
- end_of_code:
- ; .space 65536 ; space for more code
- ;end_of_code_memory:
|