dos_compilers/DX-FORTH v430/KERNEL.ASM
2024-07-09 09:07:02 -07:00

9839 lines
153 KiB
NASM

;
; DX-FORTH
;
; A direct-threaded 8086 Forth compiler for MSDOS 2.x
;
;
; Assemble to preliminary COM file using MASM or TASM:
;
; for Borland TASM 3
;
; TASMX /l KERNEL.ASM
; TLINK /t KERNEL
;
; for Microsoft MASM 5.1
;
; MASM /l KERNEL.ASM
; LINK KERNEL.OBJ
; EXE2BIN KERNEL.EXE KERNEL.COM
;
; Make compressed EXE executable:
;
; KERNEL.COM - SAVE KERNEL BYE
; DEL KERNEL.COM
;
.8086
no equ 0
yes equ not no
; Date last revised
date macro
db '2017-02-11'
endm
; Modification level
rel equ 4 ; release #
rev equ 30 ; revision #
beta equ no ; beta release
; Equates for conditional assembly
debug equ no ; debugging messages
ucase equ yes ; forth names case insensitive
fpeng equ yes ; engineering output functions
cfs equ yes ; control flow stack extensions
wopt equ yes ; warning options
ldp equ yes ; allow leading decimal point on f/p input
fpx equ no ; extra f/p functions
ints equ yes ; control interrupts
; Command-line assembly options
x = no ; show hidden words
fstack = yes ; separate floating point stack
float = yes ; include floating point routines
nfd = 6 ; max open source files (min = 2)
retro = no ; classic forth behaviours
ifdef NOHIDE
x = yes
endif
ifdef NOFLOAT
float = no
endif
ifdef NOFSTACK
fstack = no
endif
ifdef FILES
nfd = files
endif
ifdef CLASSIC
retro = yes
endif
; Memory sizes
;
; Set memory used by the forth compiler (default is 96K).
; Systems with limited memory may use reduced values e.g.
; EM=9000h, SM=4000h, HM=2800h results in a 46k footprint.
;
; EM SM HM must be a multiple of 16 bytes!
em = 0fff0h ; end of memory + 1
sm = 0b000h ; system dict. start
hm = 8000h ; header memory size
cw equ 2 ; cell size (bytes)
fw equ 4 ; float size (bytes)
; user-specified values from the command-line
ifdef ems
em = ems AND 0fff0h
endif
ifdef sms
sm = sms AND 0fff0h
endif
ifdef hms
hm = hms AND 0fff0h
endif
; Buffer sizes
us equ 128 ; user variable space
rts equ 256 ; return stack space
tibsiz equ 80 ; TIB buffer size
bufsiz equ 10*128 ; max block size (multiple of 128)
pfsiz equ 79+1 ; max path/filename size
wbsiz equ 31+5 ; min WORD buffer size
pssiz equ 255 ; max parsed string buffer size
fdsiz equ pfsiz+(4*cw) ; file descriptor size
pno equ 68 ; pictured numeric buffer size
; DOS and memory equates
if retro
psb equ em-pssiz ; buffer S"
else
psb equ em-wbsiz-pssiz ; buffer WORD S"
endif
tib equ psb-tibsiz ; TIB
sfb equ tib-bufsiz ; screen block buffer
fdbs equ sfb-(fdsiz*nfd) ; file descriptor blocks
dosfcb equ 005ch ; default file control block
dosbuf equ 0080h ; default DTA and command-line buffer
tpa equ 0100h ; program start
; Equates
init = noop ; INIT
ident = noop ; IDENT
fnu = false ; FNUMBER
fnum = 0 ; fp-stack items
fps = 0 ; fp-stack size
toppru = 0 ; top prunes
if float
maxsig = 7 ; max significant digits
init = fpini
ident = fiden
fnu = fnumb
if fstack
fnum = 6
fps = (fnum+5)*fw ; allow extra for fp display etc
endif
toppru = fprun1
endif
; ASCII characters
bel equ 07h ; bell
bs equ 08h ; backspace
tab equ 09h ; tab
lf equ 0ah ; line feed
ff equ 0ch ; form feed
cr equ 0dh ; carriage return
can equ 18h ; ctl-x
ctlz equ 1ah ; ctl-z
escape equ 1bh ; escape
;
; Forth Registers
;
; FORTH 8086 Forth preservation rules
; ----- ---- ------------------------
; IP SI Interpretive pointer. Should be preserved across
; forth words.
; SP SP Data stack pointer. Should be used only as data
; stack across forth words. May be used within forth
; words if restored before NEXT.
; RP BP Return stack pointer. Should be preserved across
; forth words.
; AX Input only when APUSH called.
; DX Input only when DPUSH called.
;
; comment conventions:
;
; a = address
; c = 8b character
; u = 16b unsigned number
; n = 16b signed number
; x = 16b signed or unsigned number
; d = 32b signed double number
; ud = 32b unsigned double number
; xd = 32b signed or unsigned number
; cfa,xt = addr of code field (execution token)
; lfa = addr of link field
; nfa = addr of name field
; pfa = addr of parameter field (body)
;
; FIG Fig-FORTH model
; F79 Forth-79 Standard
; F83 Forth-83 Standard
; F94 Forth-94 ANS FORTH Standard
;
; Memory allocation
;
; The memory above LIMIT is used only by the interpreter. This space
; is not wasted for turnkey applications as LIMIT, user variables and
; stacks are relocated to EM giving applications more free ram (as
; indicated by UNUSED). Word headers have their own segment.
;
; HM |-------------
; |
; DPH |-------------
; | word headers
; 0 |-------------
;
; EM |------------- end of memory
; | parsed string buffer
; PSB |-------------
; | terminal input buffer
; TIB |-------------
; | block buffer
; SFB |-------------
; | file descriptor blocks
; ESM |------------- end of system memory
; |
; DPS |-------------
; | system dictionary
; LIMIT |-------------
; | user variables
; R0 |-------------
; | return stack
; FS0 |-------------
; | separate fp stack
; S0 |-------------
; | data stack
; PAD |-------------
; | word and number conversion area
; DP |-------------
; | application dictionary
; 0100h |-------------
;
; Macro for generating word header
;
lastl = 0 ; initial link pointer (end of list)
hdr macro en,str,im,fl,axt
local a,b
;; en = enable hdr 0=disable
;; str = name string
;; im = immediate
;; fl = application/system flag
;; axt = alias xt
if en ;; if header enable
ifb <fl>
cseg
else
aseg
endif
cfadr = $ ;; code field address
heads segment public ;; put heads in own segment
lnk = $ ;; link address for next word
bits = 0
ifnb <im>
bits = bits+40h ;; set immediate bit
endif
ifnb <axt> ;; if alias
cfadr = axt ;; set cfa
bits = bits+80h ;; set alias bit
endif
db a ;; generate count byte
b db str ;; generate name
a = $-b+bits
dw lastl ;; generate link field
dw cfadr ;; for application words
lastl = lnk-horig
heads ends
endif
ifb <fl> ;; switch to system or application
cseg
else
aseg
endif
endm
; Macro to generate counted string
dcs macro s1,s2,s3,s4 ;; allow comma separated
local a,b
db a ;; generate count byte
b db s1
ifnb <s2>
db s2
ifnb <s3>
db s3
ifnb <s4>
db s4
endif
endif
endif
a = $-b
endm
; Macro to switch between application and system memory
cseg macro
loc = $
if loc ge (orig+sm)
pchi = $
org pclo
endif
endm
aseg macro
loc = $
if loc lt (orig+sm)
pclo = $
org pchi
endif
endm
; Macro for I/O delay to same peripheral
iodelay macro
jmp short $+2
endm
; Macro for inline NEXT
nextt macro
lodsw
jmp ax
endm
; Macro to ignore next 1 bytes
ignore1 macro
db 0a8h ;; test al,n
endm
; Macro to ignore next 2 bytes
ignore2 macro
db 0a9h ;; test ax,n
endm
; Macro to generate fdb table
gfdb macro
local a
a = fdbs
rept nfd
dw a
a = a+fdsiz
endm
endm
; Assembly initialisation
dgroup group main,heads ; put in same segment for COM file
main segment byte public 'CODE'
main ends
heads segment byte public
horig = $ ; base of segment
dnfa db 0 ; dummy nfa - don't remove!
heads ends
main segment
assume cs:main,ds:main,ss:main,es:main
org 0
orig equ $
org $+tpa
pclo = $
org sm
pchi = $
;
; Code starts here
;
cseg
start: jmp cldd
org start+3
; Video parameters - do not change
cattr db ?,? ; current video attribute 0103
cmode db ?,? ; current video mode, page 0105
wmin db ?,? ; current window min (col,row) 0107
wmax db ?,? ; current window max (col,row) 0109
db 5 dup (?) ; reserved 010B
; Temporary filename buffers
zbsiz equ pfsiz+1
zb1 db zbsiz dup (0)
zb2 db zbsiz dup (0)
tmpstk equ $-cw ; temp stack for startup & EXE load
; DXFORTH ( -- minor major )
hdr 1,'DXFORTH'
dxf: mov ax,rel
mov dx,rev
; NEXT is forth's address interpreter. For primitives, it is usually
; compiled in-line for maximum speed.
dpush: push dx ; 2PUSH
apush: push ax ; 1PUSH
; NOOP ( -- )
hdr 1,'NOOP' ; FIG
noop equ $
next: nextt ; NEXT
imode db ?,? ; initial video mode, page
iattr db ? ; initial video attribute
db 2 dup (?) ; spare
; Boot up variables used by COLD, must be in same order as USER variables
initu equ $ ; <<< beginning data
dw 3 dup (?) ; reserved for multitasking
is0 dw ? ; s0
ir0 dw ? ; r0
idp dw initdp ; dp
idps dw initdps ; dps
ivoc dw forth2 ; voc-link
ifs0 dw ? ; fs0
idph dw initdph ; dph
initu2 equ $ ; <<< end data
esm dw ? ; end of system memory
iboot dw ? ; initial boot value
dosv dw 0,0 ; DOS version (major,minor)
defdrv db ? ; default drive
scaps db ? ; COMPARE SEARCH case flag
cmdf db ? ; command line flag
kbfn db ?,? ; keyboard functions
kbpend db ? ; key pending (0 if none)
fssav dw ? ; forth stack save
ulimit dw ?,? ; LIMIT for turnkey
dw ? ; spare
dw ? ; spare
; Misc. subroutines
; set cursor position
scurs: mov ah,2
ignore2
; get cursor position
gcurs: mov ah,3
; perform int 10h using current page number
videop: mov bh,cmode+1
jmp short video
; perform INT 10h using current attribute
videoa: mov bh,cattr
; perform INT 10h saving SI, BP
video: push si
push bp
int 10h
pop bp
pop si
ret
; get video mode AL=mode AH=page BH=cols
gmode: mov ah,0fh
call video
xchg bh,ah
mov word ptr cmode,ax ; save
ret
; read BIOS tick timer AX:DX = ticks after midnight
;
; BIOS INT 1Ah AH=0 is not used as it may cause
; DOS to fail to increment the system date
if ints
tod: push ds
sub ax,ax
mov ds,ax
pushf
cli
mov dx,ds:[046ch]
mov ax,ds:[046eh]
popf
pop ds
ret
else
tod: push ds
sub ax,ax
mov ds,ax
tod1: mov ax,ds:[046eh]
mov dx,ds:[046ch]
cmp ax,ds:[046eh]
jnz tod1
pop ds
ret
endif
; wait for timer tick AX:DX = TOD
tsync: push bx
call tod
tsync1: mov bx,dx
call tod
cmp bx,dx
jz tsync1
pop bx
ret
; make uppercase AL
upc: cmp al,'a'
jc upc1
cmp al,'z'+1
jnc upc1
xor al,20h
upc1: ret
; move block down AX = src, DI = dest, CX = cnt
bmovd: push ds
pop es
bmovd1: xchg si,ax
rep movsb
mov si,ax
ret
; move block up/down AX = src, DI = dest, CX = cnt, DX = scratch
bmove: mov dx,di
sub dx,ax
cmp dx,cx
jc bmovu ; overlap and moving-up
; jmp movd
; move block down AX = src, DI = dest, CX = cnt
; increment by word NOTE: does not propagate
movd: push ds
pop es
xchg si,ax
shr cx,1
rep movsw
jnc movd1
movsb
movd1: mov si,ax
ret
; move block up AX = src, DI = dest, CX = cnt
bmovu: push ds
pop es
xchg si,ax
dec cx
add di,cx
add si,cx
inc cx
std
rep movsb
cld
mov si,ax
ret
; runtime for colon definitions
docol: sub bp,cw ; push IP onto return stack
mov [bp],si
pop si ; get new IP from 'call'
nextt
; runtime for user variables
douse: pop bx
mov ax,upp
add ax,[bx]
push ax
nextt
; EXIT ( -- ) exit colon definition
hdr 1,'EXIT'
exit: mov si,[bp] ; pop IP from return stack
; UNNEST ( -- )
hdr 1,'UNNEST'
unnest: add bp,cw
unnest1:nextt
; EXIT1 exit colon to code
exit1: push si
mov si,[bp]
add bp,cw
; EXECUTE ( xt -- )
hdr 1,'EXECUTE'
exec: ret
; @EXECUTE ( a-addr -- )
hdr 1,'@EXECUTE'
aexec: pop bx
mov cx,[bx]
jcxz unnest1
jmp cx
; clit ( -- char )
hdr x,'CLIT' ; FIG
clit: sub ax,ax
lodsb
push ax
nextt
; lit ( -- n )
hdr x,'LIT' ; FIG
lit: lodsw
push ax
nextt
; 2lit ( -- x1 x2 )
hdr x,'2LIT'
tlit: lodsw
mov dx,ax
lodsw
push ax
push dx
nextt
;
; Stack Manipulation
;
; SP@ SP! RP@ RP! >R R> R@ 2>R 2R> 2R@ DROP DUP ?DUP
; SWAP OVER ROT -ROT ROLL -ROLL PICK NIP TUCK >< 2DROP
; 2DUP 2SWAP 2OVER 2ROT 2NIP DEPTH
;
; SP@ ( -- addr )
hdr 1,'SP@'
spat: mov ax,sp ; 'push sp' won't work on 8086
jmp apush
; SP! ( addr -- )
hdr 1,'SP!'
spsto: pop ax
mov sp,ax
nextt
; RP@ ( -- addr )
hdr 1,'RP@'
rpat: push bp
nextt
; RP! ( addr -- )
hdr 1,'RP!'
rpsto: pop bp
nextt
; >R ( x -- )
hdr 1,'>R'
tor: sub bp,cw
pop [bp]
nextt
; R> ( -- x )
hdr 1,'R>'
fromr: push [bp]
add bp,cw
nextt
; R@ ( -- x )
hdr 1,'R@'
rat: push [bp]
nextt
; 2>R ( x1 x2 -- )
hdr 1,'2>R'
ttor: sub bp,cw*2
pop [bp]
pop [bp+cw]
nextt
; 2R> ( -- x1 x2 )
hdr 1,'2R>'
tfrom: push [bp+cw]
push [bp]
add bp,cw*2
nextt
; 2R@ ( -- x1 x2 )
hdr 1,'2R@'
trat: mov bx,bp
jmp tat1
; DROP ( x -- )
hdr 1,'DROP'
drop: add sp,cw
nextt
; DUP ( x -- x x )
hdr 1,'DUP'
dupp: mov bx,sp
push [bx]
nextt
; ?DUP ( x -- 0 | x x )
hdr 1,'?DUP'
qdup: mov bx,sp
mov cx,[bx]
jcxz qdup1
push cx
qdup1: nextt
; SWAP ( x1 x2 -- x2 x1 )
hdr 1,'SWAP'
swap: pop dx
pop ax
push dx
push ax
nextt
; OVER ( x1 x2 -- x1 x2 x1 )
hdr 1,'OVER'
over: mov bx,sp
push [bx+cw]
nextt
; ROT ( x1 x2 x3 -- x2 x3 x1 )
hdr 1,'ROT'
rot: pop dx
pop bx
pop ax
push bx
push dx
push ax
nextt
; -ROT ( x1 x2 x3 -- x3 x1 x2 )
hdr 1,'-ROT'
drot: pop bx
pop ax
pop dx
push bx
push dx
push ax
nextt
; ROLL ( xu xu-1 .. x0 u -- xu-1 .. x0 xu )
hdr 1,'ROLL'
roll: pop cx
;; jcxz roll2
mov di,cx
shl di,1
add di,sp
push si
lea si,[di-cw]
std
roll1: mov ax,[di]
push ds
pop es
rep movsw
cld
mov [di],ax
pop si
roll2: nextt
; -ROLL ( xu .. xu+1 x0 u -- x0 xu .. xu+1 )
hdr 1,'-ROLL'
droll: pop cx
;; jcxz roll2
mov di,sp
push si
lea si,[di+cw]
jmp roll1
; PICK ( xu .. x1 x0 u -- xu .. x1 x0 xu )
hdr 1,'PICK'
pick: pop bx
shl bx,1
add bx,sp
push [bx]
nextt
; NIP ( x1 x2 -- x2 )
hdr 1,'NIP'
nip: pop ax
add sp,cw
push ax
nextt
; TUCK ( x1 x2 -- x2 x1 x2 )
hdr 1,'TUCK'
tuck: pop ax
pop dx
push ax
push dx
push ax
nextt
; >< ( x1 -- x2 )
hdr 1,'><'
bswp: pop ax
xchg ah,al
jmp apush
; 2DROP ( x1 x2 -- )
hdr 1,'2DROP'
tdrop: add sp,cw*2
nextt
; 2DUP ( x1 x2 -- x1 x2 x1 x2 )
hdr 1,'2DUP'
tdup: mov bx,sp
push [bx+cw]
push [bx]
nextt
; 2SWAP ( x1 x2 x3 x4 -- x3 x4 x1 x2 )
hdr 1,'2SWAP'
tswap: pop bx
pop cx
pop ax
pop dx
push cx
push bx
push dx
push ax
nextt
; 2OVER ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 )
hdr 1,'2OVER'
tover: mov bx,sp
push [bx+cw*3]
push [bx+cw*2]
nextt
; 2ROT ( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 ) 5 roll 5 roll
hdr 1,'2ROT'
trot: call docol
dw clit
db 5
dw roll
dw clit
db 5
dw roll
dw exit
; 2NIP ( x1 x2 x3 x4 -- x3 x4 )
hdr 1,'2NIP'
tnip: pop ax
pop dx
add sp,cw*2
jmp dpush
; DEPTH ( -- +n ) sp@ s0 @ swap - 2/
hdr 1,'DEPTH'
depth: mov bx,upp
mov ax,[bx+6] ; S0
sub ax,sp
sar ax,1
jmp apush
;
; Memory & String Operations
;
; CSEG SSEG HSEG @ ! C@ C! 2@ 2! @L !L C@L C!L
; 2@L 2!L +! h@ h! hc@ ON OFF BLANK ERASE FILL
; LFILL CMOVE CMOVE> CMOVEL MOVE COUNT PACK PLACE
; affix SCAN SKIP -TRAILING TRIM /STRING COMPARE
; SEARCH +STRING ZCOUNT ZPLACE S.R
;
; CSEG ( -- seg ) code segment
hdr 1,'CSEG'
csegg: call docon
cseg1 dw ? ; patched
; SSEG ( -- a-addr ) search segment
hdr 1,'SSEG'
sseg: call docre
sseg1 dw ?
; HSEG ( -- seg ) heads segment
hdr 1,'HSEG'
hseg: call docon
hseg1 dw ? ; patched
; @ ( a-addr -- x )
hdr 1,'@'
at: pop bx
push [bx]
nextt
; ! ( x a-addr -- )
hdr 1,'!'
store: pop bx
pop [bx]
nextt
; C@ ( c-addr -- char )
hdr 1,'C@'
cat: pop bx
sub ax,ax
mov al,[bx]
push ax
nextt
; C! ( char c-addr -- )
hdr 1,'C!'
cstor: pop bx
pop ax
mov [bx],al
nextt
; 2@ ( a-addr -- x1 x2 )
hdr 1,'2@'
tat: pop bx
tat1: push [bx+cw]
push [bx]
nextt
; 2! ( x1 x2 a-addr -- )
hdr 1,'2!'
tstor: pop bx
pop [bx]
pop [bx+cw]
nextt
; @L ( seg offs -- x )
hdr 1,'@L'
atl: pop bx
pop ds
push [bx]
mov bx,cs
mov ds,bx
nextt
; !L ( x seg offs -- )
hdr 1,'!L'
storl: pop bx
pop ds
pop [bx]
mov bx,cs
mov ds,bx
nextt
; C@L ( seg offs -- char )
hdr 1,'C@L'
catl: pop bx
pop ds
sub ax,ax
mov al,[bx]
mov bx,cs
mov ds,bx
push ax
nextt
; C!L ( char seg offs -- )
hdr 1,'C!L'
cstorl: pop bx
pop ds
pop ax
mov [bx],al
mov bx,cs
mov ds,bx
nextt
; 2@L ( seg offs -- x1 x2 )
hdr 1,'2@L'
tatl: pop bx
pop ds
push [bx+cw]
push [bx]
mov bx,cs
mov ds,bx
nextt
; 2!L ( x1 x2 seg offs -- )
hdr 1,'2!L'
tstorl: pop bx
pop ds
pop [bx]
pop [bx+cw]
mov bx,cs
mov ds,bx
nextt
; +! ( x a-addr -- )
hdr 1,'+!'
pstor: pop bx
pop ax
add [bx],ax
nextt
; h@ ( h-addr -- x )
hdr x,'H@',,1
hat: pop bx
push word ptr hseg1
push bx
jmp atl
; h! ( x h-addr -- )
hdr x,'H!',,1
hstor: pop bx
push word ptr hseg1
push bx
jmp storl
; hc@ ( h-addr -- char )
hdr x,'HC@',,1
hcat: pop bx
push word ptr hseg1
push bx
jmp catl
; ON ( addr -- ) -1 swap !
hdr 1,'ON'
on: pop bx
on1: mov word ptr [bx],-1
nextt
; OFF ( addr -- ) 0 swap !
hdr 1,'OFF'
off: pop bx
off1: mov word ptr [bx],0
nextt
; BLANK ( c-addr u -- ) bl fill
hdr 1,'BLANK'
blank: mov al,20h
ignore2
; ERASE ( addr u -- ) 0 fill
hdr 1,'ERASE'
erase: mov al,0
ignore1
; FILL ( c-addr u char -- )
hdr 1,'FILL'
fill: pop ax
mov cx,ds
mov es,cx
pop cx
pop di
fill1: rep stosb
nextt
; LFILL ( seg offs u char -- )
hdr 1,'LFILL'
lfill: pop ax
pop cx
pop di
pop es
jmp fill1
; CMOVE ( c-addr1 c-addr2 u -- )
hdr 1,'CMOVE'
cmove: pop cx
pop di
pop ax
cmove1: call bmovd
nextt
; CMOVE> ( c-addr1 c-addr2 u -- )
hdr 1,'CMOVE>'
cmovu: pop cx
pop di
pop ax
call bmovu
nextt
; CMOVEL ( seg1 offs1 seg2 offs2 u -- )
hdr 1,'CMOVEL'
cmovl: mov bx,ds
pop cx
pop di
pop es
pop ax
pop ds
call bmovd1
mov ds,bx
nextt
; MOVE ( a-addr1 a-addr2 u -- ) >r 2dup u< if r> cmove> else r>
; cmove then
hdr 1,'MOVE'
move: pop cx
pop di
pop ax
call bmove
nextt
; COUNT ( c-addr1 -- c-addr2 u ) dup 1+ swap c@
hdr 1,'COUNT'
count: pop bx
sub ax,ax
mov al,[bx]
inc bx
push bx
jmp apush
; PACK ( c-addr1 u c-addr2 -- c-addr2 )
; 2dup 2>r 1+ swap move 2r> tuck c!
hdr 1,'PACK'
pack: pop di
pop cx
pop ax
push di
push cx
push di
inc di
call bmove
jmp cstor
; PLACE ( c-addr1 u c-addr2 -- ) pack drop
hdr 1,'PLACE'
place: call docol
dw pack,drop
dw exit
; affix ( c-addr char -- c-addr ) over count + c!
hdr x,'AFFIX' ; append char to counted string
affix: call docol ; count unchanged
dw over
dw count,plus
dw cstor
dw exit
; SCAN ( c-addr1 u1 char -- c-addr2 u2 )
hdr 1,'SCAN'
scan: pop ax
pop cx
pop di
jcxz scan1
mov es,sseg1
repnz scasb
jnz scan1
inc cx
dec di
scan1: push di
push cx
nextt
; SKIP ( c-addr1 u1 char -- c-addr2 u2 )
hdr 1,'SKIP'
skip: pop ax
pop cx
pop di
jcxz skip1
mov es,sseg1
rep scasb
jz skip1
inc cx
dec di
skip1: push di
push cx
nextt
; -TRAILING ( c-addr u1 -- c-addr u2 ) bl trim
hdr 1,'-TRAILING'
dtrai: mov al,' '
ignore1
; TRIM ( c-addr u1 char -- c-addr u2 )
hdr 1,'TRIM'
trim: pop ax
pop cx
pop di
push di
jcxz trim1
mov es,sseg1
add di,cx
dec di
std
repz scasb
cld
jz trim1
inc cx
trim1: push cx
nextt
; -BLANKS ( c-addr u1 -- c-addr u2 ) bl skip -trailing
hdr 1,'-BLANKS'
dblan: call docol
dw bll,skip
dw dtrai
dw exit
; /STRING ( c-addr1 u1 n -- c-addr2 u2 ) rot over + -rot -
hdr 1,'/STRING'
sstr: pop ax
mov bx,sp
sub [bx],ax
add [bx+cw],ax
nextt
; -caps ( -- ) disable caps COMPARE/SEARCH
hdr x,'-CAPS'
dcaps: mov al,0
ignore2
; CAPS ( -- ) enable caps COMPARE/SEARCH
hdr 1,'CAPS'
caps: mov al,1
mov scaps,al
nextt
; string compare
cseg
cmpss: cmp byte ptr scaps,0
jnz cmpnc
rep cmpsb
ret
cmpnc: push ax
cmp cx,cx ; clear S Z flags
jcxz cmpnc2
cmpnc1: lodsb
call upc
mov ah,al
mov al,es:[di]
inc di
call upc
cmp ah,al
jnz cmpnc2
loop cmpnc1
cmpnc2: pop ax
ret
; COMPARE ( c-addr1 u1 c-addr2 u2 -- -1 | 0 | 1 )
hdr 1,'COMPARE'
cmpp: mov dx,si
pop cx
pop si
pop bx
pop di
mov es,sseg1
sub ax,ax
cmp cx,bx
jz cmpp2
ja cmpp1
inc ax
jmp short cmpp2
cmpp1: dec ax
mov cx,bx
cmpp2: call cmpss
jz cmpp3
mov ax,-1
jnc cmpp3
neg ax
cmpp3: mov si,dx
push ax
jmp dcaps
; SEARCH ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 -1 | c-addr1 u1 0 )
hdr 1,'SEARCH'
sear: pop bx
pop ax
or bx,bx ; u2=0
jz sear3 ; match
pop dx
pop di
push di
push dx
push si
xchg si,ax
mov es,sseg1
sub dx,bx
js sear5 ; u2<u1
sear1: push si
push di
mov cx,bx
call cmpss
pop di
pop si
jz sear2
or dx,dx
jz sear5
inc di
dec dx
jmp sear1
sear2: pop si
pop ax
pop ax
add dx,bx
push di
push dx
sear3: mov ax,-1
sear4: push ax
jmp dcaps
sear5: pop si
sub ax,ax
jmp sear4
; +STRING ( c-addr1 u1 c-addr2 u2 -- c-addr2 u3)
; 2swap swap 2over + 2 pick cmove +
hdr 1,'+STRING'
pstr: pop dx
pop di
pop cx
pop ax
push di
add di,dx
add dx,cx
push dx
call movd
nextt
; ZCOUNT ( c-addr -- c-addr u ) dup begin count 0= until over - 1-
hdr 1,'ZCOUNT'
zcnt: pop bx
push bx
call zcnt1
jmp apush
; BX=addr AX=cnt
zcnt1: mov es,sseg1
zcnt2: sub ax,ax
zcnt3: cmp byte ptr es:[bx],0
jz zcnt4
inc bx
inc ax
jnz zcnt3
zcnt4: ret
; ZPLACE ( c-addr1 u c-addr2 -- ) 2dup + >r swap cmove 0 r> c!
hdr 1,'ZPLACE'
zplace: pop di
pop cx
pop ax
call movd
mov byte ptr [di],0
nextt
; S.R ( c-addr n1 n2 -- ) over - spaces type
hdr 1,'S.R' ; type string right-justified
sdotr: call docol
dw over,subb
dw spacs
dw typee
dw exit
;
; Comparison Functions
;
; D0= 0= 0<> = <> 0< 0> < > U< U> MIN MAX UMIN UMAX
; WITHIN BETWEEN D= D0< D< DU< DMIN DMAX
;
; D0= ( d -- flag ) or 0=
hdr 1,'D0='
dzequ: pop ax
pop bx
or ax,bx
ignore1
; 0= ( x -- flag )
hdr 1,'0='
zequ: pop ax
zequ1: sub ax,1
sbb ax,ax
push ax
nextt
; 0<> ( x -- flag )
hdr 1,'0<>'
zneq: pop ax
zneq1: neg ax
sbb ax,ax
push ax
nextt
; = ( x1 x2 -- flag )
hdr 1,'='
equal: pop ax
pop bx
sub ax,bx
sub ax,1
sbb ax,ax
push ax
nextt
; <> ( x1 x2 -- flag )
hdr 1,'<>'
nequ: pop ax
pop bx
sub ax,bx
neg ax
sbb ax,ax
push ax
nextt
; 0< ( n -- flag )
hdr 1,'0<'
zless: pop ax
cwd
push dx
nextt
; 0> ( n -- flag )
hdr 1,'0>'
zgrea: pop bx
sub cx,cx
zgrea1: sub ax,ax
cmp bx,cx
jng zgrea2
dec ax
zgrea2: push ax
nextt
; < ( n1 n2 -- flag )
hdr 1,'<'
less: pop bx
pop cx
jmp short zgrea1
; > ( n1 n2 -- flag )
hdr 1,'>'
great: pop cx
pop bx
jmp short zgrea1
; U< ( u1 u2 -- flag )
hdr 1,'U<'
uless: pop ax
pop bx
sub bx,ax
sbb ax,ax
push ax
nextt
; U> ( u1 u2 -- flag )
hdr 1,'U>'
ugrea: pop ax
pop bx
sub ax,bx
sbb ax,ax
push ax
nextt
; MIN ( n1 n2 -- n1 | n2 ) 2dup > if swap then drop
hdr 1,'MIN'
min: pop ax
pop bx
cmp ax,bx
jl min1
mov ax,bx
min1: push ax
nextt
; 0max ( n1 -- n2 ) 0 max
hdr x,'0MAX'
zmax: sub ax,ax
ignore1
; MAX ( n1 n2 -- n1 | n2 ) 2dup < if swap then drop
hdr 1,'MAX'
max: pop ax
pop bx
cmp ax,bx
jg max1
mov ax,bx
max1: push ax
nextt
; UMIN ( u1 u2 -- u1 | u2 ) 2dup u> if swap then drop
hdr 1,'UMIN'
umin: pop ax
pop bx
cmp ax,bx
jc umin1
mov ax,bx
umin1: push ax
nextt
; UMAX ( u1 u2 -- u1 | u2 ) 2dup u< if swap then drop
hdr 1,'UMAX'
umax: pop ax
pop bx
cmp ax,bx
ja umax1
mov ax,bx
umax1: push ax
nextt
; WITHIN ( x1 x2 x3 -- flag ) over - >r - r> u<
hdr 1,'WITHIN'
within: pop bx
pop ax
pop cx
sub cx,ax
sub bx,ax
cmp cx,bx
sbb ax,ax
jmp apush
if 1
; BETWEEN ( x1 x2 x3 -- flag ) over - -rot - u< 0=
hdr 1,'BETWEEN'
betw: pop bx
pop ax
pop cx
sub bx,ax
sub cx,ax
cmp bx,cx
cmc
sbb ax,ax
jmp apush
endif
; D= ( d1 d2 -- flag ) d- d0=
hdr 1,'D='
dequ: call docol
dw dsub
dw dzequ
dw exit
; D0< ( d -- flag ) nip 0<
hdr 1,'D0<'
dzle: pop ax
pop bx
cwd
push dx
nextt
; D< ( d1 d2 -- flag )
hdr 1,'D<'
dless: pop dx
pop bx
pop cx
pop ax
sub ax,bx
sbb cx,dx
jl dless1
jmp false
dless1: jmp true
; DU< ( ud1 ud2 -- flag )
hdr 1,'DU<'
dules: pop dx
pop bx
pop cx
pop ax
sub ax,bx
sbb cx,dx
sbb ax,ax
jmp apush
; DMIN ( d1 d2 -- d1 | d2 ) 2over 2over d< 0= if 2swap then 2drop
hdr 1,'DMIN'
dmin: call docol
dw tover,tover
dw dless,zequ
dmin1 dw zbran,dmin2
dw tswap
dmin2 dw tdrop
dw exit
; DMAX ( d1 d2 -- d1 | d2 ) 2over 2over d< if 2swap then 2drop
hdr 1,'DMAX'
dmax: call docol
dw tover,tover
dw dless
dw bran,dmin1
;
; Arithmetic and Logical Functions
;
; AND OR XOR INVERT NOT S>D D>S NEGATE ABS DNEGATE DABS +
; - M+ D+ D- 1+ 2+ 1- 2- UM* M* UM/MOD SM/REM FM/MOD
; */MOD */ /MOD / MOD M*/ 2* 2/ U2/ D2* D2/ LSHIFT RSHIFT
;
; AND ( x1 x2 -- x3 )
hdr 1,'AND'
andd: pop ax
pop bx
and ax,bx
push ax
nextt
; OR ( x1 x2 -- x3 )
hdr 1,'OR'
orr: pop ax
pop bx
or ax,bx
push ax
nextt
; XOR ( x1 x2 -- x3 )
hdr 1,'XOR'
xorr: pop ax
pop bx
xor ax,bx
push ax
nextt
; INVERT ( x1 -- x2 ) one's complement
hdr 1,'INVERT'
invert: pop ax
not ax
push ax
nextt
; NOT ( x1 -- x2 ) aka 0= not
hdr 1,'NOT',,,zequ ; F79 NOT
nott equ zequ
; S>D ( n -- d )
hdr 1,'S>D'
stod: pop ax
cwd
push ax
push dx
nextt
; D>S ( d -- n ) aka drop d>s
hdr 1,'D>S',,,drop
dtos equ drop
; NEGATE ( n1 -- n2 )
hdr 1,'NEGATE'
negat: pop ax
neg ax
push ax
nextt
; ABS ( n -- +n )
hdr 1,'ABS'
abss: pop ax
cwd
xor ax,dx
sub ax,dx
jmp apush
; DNEGATE ( d1 -- d2 )
hdr 1,'DNEGATE'
dnegat: pop ax
dnegat1:pop dx
neg ax
neg dx
sbb ax,0
jmp dpush
; DABS ( d -- +d )
hdr 1,'DABS'
dabs: pop ax
or ax,ax
js dnegat1
jmp apush
; + ( x1 x2 -- x3 )
hdr 1,'+'
plus: pop ax
pop bx
add ax,bx
push ax
nextt
; - ( x1 x2 -- x3 )
hdr 1,'-'
subb: pop dx
pop ax
sub ax,dx
push ax
nextt
; M+ ( xd1 n -- xd2 ) s>d d+
hdr 1,'M+'
mplus: pop ax
cwd
ignore2
; D+ ( xd1 xd2 -- xd3 )
hdr 1,'D+'
dplus: pop dx
pop ax
mov bx,sp
add [bx+cw],ax
adc [bx],dx
nextt
; D- ( xd1 xd2 -- xd3 ) dnegate d+
hdr 1,'D-'
dsub: pop dx
pop ax
mov bx,sp
sub [bx+cw],ax
sbb [bx],dx
nextt
; 1+ ( x1 -- x2 )
hdr 1,'1+'
onep: pop ax
inc ax
push ax
nextt
; 2+ ( x1 -- x2 )
hdr 1,'2+'
twop: pop ax
add ax,2
push ax
nextt
; 1- ( x1 -- x2 )
hdr 1,'1-'
onem: pop ax
dec ax
push ax
nextt
; 2- ( x1 -- x2 )
hdr 1,'2-'
twom: pop ax
sub ax,2
push ax
nextt
; UM* ( u1 u2 -- ud )
hdr 1,'UM*'
umstr: pop ax
pop bx
mul bx
push ax
push dx
nextt
; M* ( n1 n2 -- d )
hdr 1,'M*'
mstar: pop ax
pop bx
imul bx
push ax
push dx
nextt
; * ( x1 x2 -- x3 ) um* drop
hdr 1,'*'
star: pop ax
pop bx
mul bx
push ax
nextt
; UM/MOD ( ud u1 -- u2 u3 )
hdr 1,'UM/MOD'
umslm: pop bx
pop dx
pop ax
cmp dx,bx ; divide zero or overflow
jnc cverr
div bx
push dx
push ax
nextt
cseg
msm: mov di,dx
mov cx,bx
or dx,dx
jns msm1
sub dx,dx
neg ax
sbb dx,di
msm1: or bx,bx
jns msm2
neg bx
msm2: cmp dx,bx ; overflow?
jnc cverr0
div bx
or di,di ; sign remainder
jns msm3
neg dx
msm3: xor di,cx ; sign quotient
jns msm4
neg ax
ret
msm4: pop di
jmp dpush
; math or conversion error - set regs to -1
cverr0: pop ax
cverr: mov ax,-1
cwd
jmp dpush
; SM/REM ( d n1 -- n2 n3 )
hdr 1,'SM/REM'
smrem: pop bx
pop dx
pop ax
smrem1: call msm
jmp dpush
; FM/MOD ( d n1 -- n2 n3 )
hdr 1,'FM/MOD'
fmmod: pop bx
pop dx
pop ax
fmmod1: call msm
or dx,dx ; floor
jz fmmod2
dec ax
add dx,cx
xor di,ax ; overflow?
js cverr
fmmod2: jmp dpush
; */MOD ( n1 n2 n3 -- n4 n5 ) >r m* r> sm/rem
hdr 1,'*/MOD'
ssmod: pop bx
pop ax
pop cx
imul cx
jmp smrem1
; */ ( n1 n2 n3 -- n4 ) */mod nip
hdr 1,'*/'
ssla: call docol
dw ssmod,nip
dw exit
; /MOD ( n1 n2 -- n3 n4 ) >r s>d r> sm/rem
hdr 1,'/MOD'
slmod: pop bx
pop ax
cwd
jmp smrem1
; / ( n1 n2 -- n3 ) /mod nip
hdr 1,'/'
slash: call docol
dw slmod,nip
dw exit
; MOD ( n1 n2 -- n3 ) /mod drop
hdr 1,'MOD'
modd: call docol
dw slmod,drop
dw exit
; M*/ ( d1 n1 +n2 -- d2 ) >r 2dup xor swap abs >r -rot dabs
; swap r@ um* rot r> um* rot 0 d+ r@
; um/mod -rot r> um/mod nip swap rot
; 0< if dnegate then
hdr 1,'M*/'
mssl: pop di
pop bx
pop cx
pop ax
mov dx,cx
xor dx,bx
pushf
or bx,bx
jns mssl1
neg bx
mssl1: or cx,cx
jns mssl2
neg cx
neg ax
sbb cx,0
mssl2: mul bx
push dx
xchg cx,ax
mul bx
pop bx
add ax,bx
adc dx,0
cmp dx,di
jnc mssl5
div di
xchg ax,cx
cmp dx,di
jnc mssl5
div di
popf
jns mssl4
; if floord
; or dx,dx
; jz mssl3
; add ax,1
; adc cx,0
; endif
mssl3: neg cx
neg ax
sbb cx,0
mssl4: push ax
push cx
nextt
mssl5: jmp cverr0
; 2* ( x1 -- x2 )
hdr 1,'2*'
tstar: pop ax
shl ax,1
push ax
nextt
; 2/ ( n1 -- n2 )
hdr 1,'2/'
twodiv: pop ax
sar ax,1
push ax
nextt
; U2/ ( u1 -- u2 )
hdr 1,'U2/'
utdiv: pop ax
shr ax,1
push ax
nextt
; D2* ( xd1 -- xd2 )
hdr 1,'D2*'
dtstr: pop ax
pop dx
shl dx,1
rcl ax,1
jmp dpush
; D2/ ( d1 -- d2 )
hdr 1,'D2/'
dtdiv: pop ax
pop dx
sar ax,1
rcr dx,1
jmp dpush
; LSHIFT ( x1 u -- x2 )
hdr 1,'LSHIFT'
lsh: pop cx
pop ax
shl ax,cl
push ax
nextt
; RSHIFT ( x1 u -- x2 )
hdr 1,'RSHIFT'
rsh: pop cx
pop ax
shr ax,cl
push ax
nextt
;
; Numeric Conversion
;
; BINARY HEX DECIMAL digit >NUMBER NUMBER? <# #> +hold
; # HOLD SIGN #S SHOLD NHOLD decimal?
;
; BINARY ( -- ) 2 base !
hdr 1,'BINARY'
bin: mov al,2
ignore2
; HEX ( -- ) 16 base !
hdr 1,'HEX'
hex: mov al,16
ignore2
; DECIMAL ( -- ) 10 base !
hdr 1,'DECIMAL'
decim: mov al,10
cbw
push ax
call docol
dw base,store
dw exit
; digit ( char base -- u true | false )
hdr x,'DIGIT'
digit: pop dx
pop ax
call upc ; make uppercase
sub al,'0'
jc digit2
cmp al,10
jc digit1
sub al,7
cmp al,10
jc digit2
digit1: cmp al,dl
jnc digit2
sub ah,ah
push ax
jmp true
digit2: jmp false
; >NUMBER ( d1 addr1 u1 -- d2 addr2 u2 )
; begin dup while over c@ base @ digit while
; >r 2swap r> swap base @ um* drop rot base @
; um* d+ 2swap 1 /string 1 dpl +! repeat then
hdr 1,'>NUMBER'
tonum: call docol
tonum1 dw dupp ; begin
dw zbran,tonum2 ; while
dw over,cat
dw base,at
dw digit
dw zbran,tonum2 ; while
dw tor
dw tswap,fromr
dw swap
dw base,at
dw umstr,drop
dw rot
dw base,at
dw umstr
dw dplus
dw tswap
dw one,sstr
dw one,dpl,pstor
dw bran,tonum1 ; repeat
tonum2 dw exit ; then
; NUMBER? ( c-addr u -- d -1 | 0 )
; over c@ [char] - = over 0> and dup >r 1
; and /string over c@ [char] . > and 0 0
; 2swap ?dup if >number dpl on dup if 1-
; over c@ [char] . - or dpl off then while
; then r> 2drop 2drop false else drop r> if
; dnegate then true then
hdr 1,'NUMBER?'
numq: call docol ; convert string to double number
dw over,cat
dw clit
db '-'
dw equal
dw over,zgrea
dw andd
dw dupp,tor
dw one,andd
dw sstr
dw over,cat
dw clit
db '.'
dw great,andd
dw zero,zero
dw tswap
dw qdup
dw zbran,numq2
dw tonum
dw dpl,on
dw dupp
dw zbran,numq1
dw onem
dw over,cat
dw clit
db '.'
dw subb,orr
dw dpl,off
numq1 dw zbran,numq3
numq2 dw fromr
dw tdrop,tdrop
dw false
dw bran,numq5
numq3 dw drop
dw fromr
dw zbran,numq4
dw dnegat
numq4 dw true
numq5 dw exit
; <# ( -- ) pad hld !
hdr 1,'<#'
bdigs: call docol
dw pad
dw hld,store
dw exit
; #> ( d -- c-addr u ) 2drop hld @ pad over -
hdr 1,'#>'
edigs: call docol
dw tdrop
dw hld,at
dw pad
dw over
dw subb
dw exit
; +hold ( +n -- c-addr ) negate hld tuck +! @ dup dp @ u<
; abort" HOLD buffer overflow"
hdr x,'+HOLD'
phld: call docol
dw negat
dw hld,tuck
dw pstor
dw at,dupp
dw dpp,at,uless
dw pabq
dcs 'HOLD buffer overflow'
dw exit
; # ( ud1 -- ud2 ) 0 base @ um/mod >r base @ um/mod r>
; rot dup 9 > 7 and + [char] 0 + hold
hdr 1,'#'
dig: pop ax
pop bx
mov di,upp
add di,24 ; BASE
sub dx,dx
div word ptr [di]
xchg ax,bx
div word ptr [di]
push ax
push bx
cmp dl,9
jna dig1
add dl,7
dig1: add dl,'0'
push dx
; jmp hold
; HOLD ( char -- ) 1 +hold c!
hdr 1,'HOLD'
hold: call docol
dw one,phld
dw cstor
dw exit
; SIGN ( n -- ) 0< if [char] - hold then
hdr 1,'SIGN'
sign: call docol
dw zless
dw zbran,sign1
dw clit
db '-'
dw hold
sign1 dw exit
; #S ( ud -- 0 0 ) begin # 2dup d0= until
hdr 1,'#S'
digs: call docol
digs1 dw dig
dw tdup,dzequ
dw zbran,digs1
dw exit
; SHOLD ( c-addr u -- ) dup +hold swap move
hdr 1,'SHOLD' ; hold string
shold: call docol
dw dupp,phld
dw swap,move
dw exit
; NHOLD ( n char -- ) over +hold -rot fill
hdr 1,'NHOLD' ; hold n characters
nhold: call docol
dw over,phld
dw drot,fill
dw exit
; decimal? ( -- flag ) base @ 10 =
hdr x,'DECIMAL?'
dcmq: call docol
dw base,at ; decimal base?
dw clit
db 10
dw equal
dw exit
;
; Control Structures
;
; (of) branch ?branch (loop) (+loop) UNLOOP (leave) (?do) (do)
; BAL +bal -bal ?BAL ?depth ?orig ?dest BEGIN >MARK <RESOLVE
; THEN END IF AHEAD ELSE UNTIL AGAIN WHILE REPEAT lv DO ?DO
; I I' J LEAVE LOOP +LOOP BOUNDS CS-PICK CS-ROLL CS-DROP #cs
; CS-PUSH CS-POP CS-MARK CS-TEST COND THENS CASE ENDCASE OF
; ENDOF [ELSE] [IF] [THEN]
;
; (of) ( x1 x2 -- | x1 )
hdr x,'(OF)'
pof: pop bx
pop ax
cmp ax,bx
jz zbran1
push ax
; jmp bran
; branch ( -- )
hdr x,'BRANCH'
bran: mov si,[si]
nextt
; ?branch ( flag -- )
hdr x,'?BRANCH'
zbran: pop cx
jcxz bran
zbran1: add si,cw
nextt
; (loop) ( -- )
hdr x,'(LOOP)'
xloop: mov ax,1
ignore1
; (+loop) ( n -- )
hdr x,'(+LOOP)'
xploo: pop ax
add [bp],ax
jno bran
add si,cw
; jmp unloo
; UNLOOP ( -- )
hdr 1,'UNLOOP'
unloo: add bp,cw*2
nextt
; (leave) ( -- )
hdr x,'(LEAVE)'
pleav: mov bx,[si]
mov si,[bx]
jmp unloo
; (?do) ( x1 x2 -- )
hdr x,'(?DO)'
xqdo: pop dx
pop bx
cmp bx,dx
jz bran
ignore2
; (do) ( x1 x2 -- )
hdr x,'(DO)'
xdo: pop dx
pop bx
xchg bp,sp
add bx,8000h
push bx
sub dx,bx
push dx
xchg bp,sp
lodsw
nextt
; BAL ( -- addr )
hdr 1,'BAL',,1
bal: call docre
bal1 dw ?
; +bal ( -- ) 1 bal +!
hdr x,'+BAL',,1
pbal: inc word ptr bal1
nextt
; -bal ( -- ) -1 bal +!
hdr x,'-BAL',,1
dbal: dec word ptr bal1
nextt
; ?BAL ( flag -- ) check? and
; abort" definition unbalanced"
hdr 1,'?BAL',,1
qbal: call docol
dw chkq,andd
dw pabq
dcs 'definition unbalanced'
dw exit
; ?depth ( x -- x ) ?comp depth 0= ?bal
hdr x,'?DEPTH',,1
qdep: call docol
dw qcomp
dw depth,zequ
dw qbal
dw exit
; ?orig ( orig -- orig ) ?depth dup @ ?bal
hdr x,'?ORIG',,1
qorig: call docol
dw qdep
dw dupp,at
dw qbal
dw exit
; ?dest ( dest -- dest ) ?depth dup @ 0= ?bal
hdr x,'?DEST',,1
qdest: call docol
dw qdep
dw dupp,at
dw zequ
dw qbal
dw exit
; BEGIN ( -- dest ) ?comp here +bal ;immediate
hdr 1,'BEGIN',1,1
begin: call docol
dw qcomp
dw here
dw pbal
dw exit
; >MARK ( -- orig ) postpone begin 0 ,
hdr 1,'>MARK',,1
fmark: call docol
dw begin
dw zero
dw comma
dw exit
; <RESOLVE ( dest -- ) ?dest , -bal
hdr 1,'<RESOLVE',,1
bresol: call docol
dw qdest
dw comma
dw dbal
dw exit
; THEN ( orig -- ) ?orig here swap ! -bal ;immediate
hdr 1,'THEN',1,1
then: call docol
dw qorig
dw here
dw swap,store
dw dbal
dw exit
; END ( orig -- ) postpone exit postpone then
; ;immediate
hdr 1,'END',1,1
endd: call docol
dw comp,exit
dw then
dw exit
; IF ( -- orig ) postpone ?branch >mark
; ;immediate
hdr 1,'IF',1,1
iff: call docol
dw comp,zbran
dw fmark
dw exit
; AHEAD ( -- orig ) postpone branch >mark
; ;immediate
hdr 1,'AHEAD',1,1
ahead: call docol
dw comp,bran
dw fmark
dw exit
; ELSE ( orig1 -- orig2 ) ?orig postpone ahead swap postpone
; then ;immediate
hdr 1,'ELSE',1,1
elsee: call docol
dw qorig
dw ahead
dw swap
dw then
dw exit
; UNTIL ( dest -- ) postpone ?branch <resolve
; ;immediate
hdr 1,'UNTIL',1,1
until: mov ax,offset zbran
until1: push ax
call docol
dw comxt
dw bresol
dw exit
; AGAIN ( dest -- ) postpone branch <resolve ;immediate
hdr 1,'AGAIN',1,1
again: mov ax,offset bran
jmp until1
; WHILE ( x -- orig x ) ?depth postpone if swap ;immediate
hdr 1,'WHILE',1,1
whilee: call docol
dw qdep
dw iff
dw swap
dw exit
; REPEAT ( orig dest -- ) postpone again postpone then
; ;immediate
hdr 1,'REPEAT',1,1
repeatt:call docol
dw again
dw then
dw exit
; lv ( -- addr ) 0 value lv
hdr x,'LV',,1
lvv: call doval
dw 0
; DO ( -- orig dest ) postpone (do) lv >mark dup to lv
; postpone begin ;immediate
hdr 1,'DO',1,1
do: mov ax,offset xdo
do1: push ax
call docol
dw comxt
dw lvv
dw fmark
dw dupp
dw pto,lvv
dw begin
dw exit
; ?DO ( -- orig dest ) postpone (?do) lv >mark dup to lv
; postpone begin ;immediate
hdr 1,'?DO',1,1
qdo: mov ax,offset xqdo
jmp do1
; I ( -- x )
hdr 1,'I'
ido: mov ax,[bp]
add ax,[bp+cw]
push ax
nextt
; I' ( -- x )
hdr 1,'I'''
idot: mov ax,[bp+cw]
sub ax,8000h
jmp apush
; J ( -- x )
hdr 1,'J'
jdo: mov ax,[bp+cw*2]
add ax,[bp+cw*3]
push ax
nextt
; LEAVE ( -- ) postpone (leave) lv ?orig ,
; ;immediate
hdr 1,'LEAVE',1,1
leavee: call docol
dw comp,pleav
dw lvv
dw qorig
dw comma
dw exit
; LOOP ( addr1 addr2 -- ) postpone (loop) <resolve
; postpone then to lv ;immediate
hdr 1,'LOOP',1,1
loopp: mov ax,offset xloop
loopp1: push ax
call docol
dw comxt
dw bresol
dw then
dw pto,lvv
dw exit
; +LOOP ( addr1 addr2 -- ) postpone (+loop) <resolve
; postpone then to lv ;immediate
hdr 1,'+LOOP',1,1
ploop: mov ax,offset xploo
jmp loopp1
; BOUNDS ( addr1 u -- addr1+u a1 ) over + swap
hdr 1,'BOUNDS'
bounds: pop dx
pop ax
add dx,ax
jmp dpush
if cfs
; CS-PICK pick +bal
hdr 1,'CS-PICK',,1
cspic: inc word ptr bal1
jmp pick
; CS-ROLL aka roll cs-roll
hdr 1,'CS-ROLL',,,roll
csrol equ roll
; CS-DROP drop -bal
hdr 1,'CS-DROP',,1
csdro: pop ax
jmp dbal
; #cs ( -- cells ) sp@ csp cell+ @ - negate 2/ 1- 0 max
hdr x,'#CS',,1
ncs: mov ax,cfz1
sub ax,sp
sar ax,1
dec ax
jns ncs1
sub ax,ax
ncs1: jmp apush
; CS-PUSH #cs -roll
hdr 1,'CS-PUSH',,1
cspush: call docol
dw ncs
dw droll
dw exit
; CS-POP #cs roll
hdr 1,'CS-POP',,1
cspop: call docol
dw ncs
dw roll
dw exit
; CS-MARK 0 +bal
hdr 1,'CS-MARK',,1
csm: sub ax,ax
push ax
jmp pbal
; CS-TEST ?depth dup 0<>
hdr 1,'CS-TEST',,1
cstes: call docol
dw qdep
dw dupp
dw zneq
dw exit
; COND ?comp cs-mark immediate
hdr 1,'COND',1,1
cond: call docol
dw qcomp
dw csm
dw exit
; THENS begin cs-test while postpone then
; repeat cs-drop ;immediate
hdr 1,'THENS',1,1
thens: call docol
thens1 dw cstes
dw zbran,thens2
dw then
dw bran,thens1
thens2 dw csdro
dw exit
else
; COND ?comp 0 +bal ;immediate
hdr 1,'COND',1,1
cond: call docol
dw qcomp
dw zero
dw pbal
dw exit
; THENS begin ?depth ?dup while postpone then
; repeat -bal ;immediate
hdr 1,'THENS',1,1
thens: call docol
thens1 dw qdep
dw qdup
dw zbran,thens2
dw then
dw bran,thens1
thens2 dw dbal
dw exit
endif
; Eaker/ANS CASE support
; OF ( -- addr ) postpone (of) >mark ;immediate
hdr 1,'OF',1,1
of: call docol
dw comp,pof
dw fmark
dw exit
; ENDOF ( addr1 -- addr2 ) aka else endof
hdr 1,'ENDOF',1,,elsee
endof equ elsee
; CASE ( -- sys ) aka cond case
hdr 1,'CASE',1,,cond
casee equ cond
; ENDCASE ( sys -- ) postpone drop postpone thens
; ;immediate
hdr 1,'ENDCASE',1,1
endc: call docol
dw comp,drop
dw thens
dw exit
; [ELSE] ( -- ) 1 begin token 2dup upper dup if 2dup
; s" [IF]" compare if 2dup s" [ELSE]"
; compare if s" [THEN]" compare 0= else
; 2drop dup 1 = then else 2drop 1 then +
; else 2drop refill and then ?dup 0= until
; ;immediate
hdr 1,'[ELSE]',1,1
pels: call docol
dw one
pels1 dw token
if ucase
dw tdup,upper
endif
dw dupp
dw zbran,pels6
dw tdup
dw psqot
dcs '[IF]'
dw cmpp
dw zbran,pels4
dw tdup
dw psqot
dcs '[ELSE]'
dw cmpp
dw zbran,pels2
dw psqot
dcs '[THEN]'
dw cmpp,zequ
dw bran,pels3
pels2 dw tdrop
dw dupp,one,equal
pels3 dw bran,pels5
pels4 dw tdrop,one
pels5 dw plus
dw bran,pels7
pels6 dw tdrop
dw refil,andd
pels7 dw qdup,zequ
dw zbran,pels1
dw exit
; [IF] ( flag -- ) 0= if postpone [else] then ;immediate
hdr 1,'[IF]',1,1
pif: pop cx
jcxz pels
nextt
; [THEN] ( -- ) aka noop [then] immediate
hdr 1,'[THEN]',1,,noop
pthen equ next
;
; Numeric Output
;
; (U.) (D.) U. D. U.R D.R .R (.) ? .
;
; (U.) ( u -- ) 0 (d.)
hdr 1,'(U.)'
pudot: sub ax,ax
push ax
; jmp pddot
; (D.) ( d -- c-addr u ) tuck dabs <# #s rot sign #>
hdr 1,'(D.)'
pddot: call docol
dw tuck
dw dabs
dw bdigs
dw digs
dw rot,sign
dw edigs
dw exit
; U. ( u -- ) 0 d.
hdr 1,'U.'
udot: sub ax,ax
push ax
; jmp ddot
; D. ( d -- ) (d.) type space
hdr 1,'D.'
ddot: call docol
dw pddot
ddot1 dw typee,space
dw exit
; U.R ( u1 u2 -- ) 0 swap d.r
hdr 1,'U.R'
udotr: pop ax
sub dx,dx
push dx
push ax
; jmp ddotr
; D.R ( d n -- ) >r (d.) r> s.r
hdr 1,'D.R'
ddotr: call docol
dw tor
dw pddot
ddotr1 dw fromr
dw sdotr
dw exit
; .R ( n u -- ) >r s>d r> d.r
hdr 1,'.R'
dotr: pop bx
pop ax
cwd
push ax
push dx
push bx
jmp ddotr
; (.) ( n -- ) s>d (d.)
hdr 1,'(.)'
pdot: call docol
dw stod,pddot
dw exit
; ? ( addr -- ) @ .
hdr 1,'?'
ques: pop bx
push [bx]
; jmp dot
; . ( x -- ) decimal? if s>d d. end u.
hdr 1,'.'
dot: call docol
dw dcmq
dw zbran,dot1
dw stod,ddot
dw exit
dot1 dw udot
dw exit
; DOSVER ( -- minor major )
hdr 1,'DOSVER'
dosver: mov bx,offset dosv
jmp tat1
cseg
regs dw 10 dup (?) ; cpu registers
; DOSCALL ( u -- )
hdr 1,'DOSCALL'
dosc: pop ax
mov byte ptr regs+1,al
mov regs+14,ds
mov al,21h
ignore1
; INTCALL ( u -- )
hdr 1,'INTCALL'
intc: pop ax
push si
push bp
push cs
mov byte ptr intc1+1,al
mov si,offset regs
lodsw
push ax ; AX
lodsw
mov bx,ax
lodsw
mov cx,ax
lodsw
mov dx,ax
lodsw
mov bp,ax
lodsw
push ax ; SI
lodsw
mov di,ax
lodsw
push ax ; DS
lodsw
mov es,ax
pop ds
pop si
pop ax
mov cs:fssav,sp
intc1: int 0 ; NOTE: self-modifying code
cli
mov ss,cs:cseg1 ; restore SS:SP
mov sp,cs:fssav ; for DOS 2.x
sti
pushf
push es
push di
push cs
pop es
mov di,offset regs
cld
stosw
mov ax,bx
stosw
mov ax,cx
stosw
mov ax,dx
stosw
mov ax,bp
stosw
mov ax,si
stosw
pop ax ; DI
stosw
mov ax,ds
stosw
pop ax ; ES
stosw
pop ax ; flags
stosw
pop ds
pop bp
pop si
nextt
hdr 1,'''FLAGS'
tfl: mov al,18
ignore2
hdr 1,'''ES'
tes: mov al,16
ignore2
hdr 1,'''DS'
tds: mov al,14
ignore2
hdr 1,'''DI'
tdi: mov al,12
ignore2
hdr 1,'''SI'
tsi: mov al,10
ignore2
hdr 1,'''BP'
tbp: mov al,8
ignore2
hdr 1,'''DH'
tdh: mov al,7
ignore2
hdr 1,'''DX'
tdx: mov al,6
ignore2
hdr 1,'''CH'
tch: mov al,5
ignore2
hdr 1,'''CX'
tcx: mov al,4
ignore2
hdr 1,'''BH'
tbh: mov al,3
ignore2
hdr 1,'''BX'
tbx: mov al,2
ignore2
hdr 1,'''AH'
tah: mov al,1
ignore2
hdr 1,'''AX'
tax: mov al,0
cbw
add ax,offset regs
jmp apush
; DOSERR? ( -- ior ) 'flags @ 1 and if 'ax @ else 0 then
hdr 1,'DOSERR?'
doserr: test byte ptr regs+18,1
jz doserr2
mov ax,regs
stc
; test for DOS error
doserr1:jnc doserr2
mov ah,0feh ; convert DOS error# to ior value
jmp apush
doserr2:jmp zero
; Port fetch and store instructions
; PC@ ( p-addr -- 8bit )
hdr 1,'PC@' ; FIG P@
pcat: pop dx
sub ax,ax
in al,dx
push ax
nextt
; PC! ( 8bit p-addr -- )
hdr 1,'PC!' ; FIG P!
pcsto: pop dx
pop ax
out dx,al
nextt
; P@ ( p-addr -- 16bit )
hdr 1,'P@'
pat: pop dx
in ax,dx
push ax
nextt
; P! ( 16bit p-addr -- )
hdr 1,'P!'
psto: pop dx
pop ax
out dx,ax
nextt
; TICKS ( -- d )
hdr 1,'TICKS'
ticks: call tod
jmp dpush
; WAIT-TICK ( -- )
hdr 1,'WAIT-TICK'
wtick: call tsync
nextt
; (/MS) ( -- ) detect timer0 mode and adjust MS
hdr x,'(/MS)'
psms: mov ax,nmscon ; assume mode 3
mov word ptr ms5,ax
mov ntmode,3
call tsync ; sync to tick timer
push dx ; TOD
push ax
mov cx,280 ; wait ~5 ticks
call ms1
call tod
pop cx
cmp ax,cx
jnc psms1
add dx,0b0h ; midnight crossed
psms1: pop ax
sub dx,ax
cmp dx,8
jc psms2
sar word ptr ms5,1 ; was mode 2
dec ntmode
psms2: nextt
; /MS ( -- ) detect timer0 mode and adjust MS
hdr 1,'/MS'
smss: call aexec
dw psms
; (BEEP) ( -- )
hdr x,'(BEEP)'
beep0: mov ax,75
push ax
mov cx,600
call sound1
; (MS) ( ms -- )
hdr x,'(MS)'
ms0: pop cx
push tnext1
; delay (ms) in CX ; uses timer 0
ms1: jcxz ms6
ms2: push cx
test cl,3 ; PAUSE each 4mS for
jnz ms3 ; multitasking
call docol
dw pause
dw exit1
ms3: call ms7
mov cx,bx
ms4: call ms7
sub bx,cx
cmp bx,-2386 ; patched by COLD
ms5 equ $-cw
jnc ms4
pop cx
loop ms2
ms6: ret
if ints
ms7: pushf
cli
sub al,al
out 43h,al
iodelay
in al,40h
mov bl,al
iodelay
in al,40h
mov bh,al
popf
ret
else
ms7: push ds
sub bx,bx
mov ds,bx
ms8: mov bx,ds:[046ch]
sub al,al
out 43h,al
iodelay
in al,40h
mov ah,al
iodelay
in al,40h
cmp bx,ds:[046ch]
jnz ms8
mov bh,al
mov bl,ah
pop ds
ret
endif
; (SOUND) ( freq ms -- )
hdr x,'(SOUND)'
sound0: pop ax
pop cx
push tnext1
sound1: push ax ; uses timer 2
mov dx,12h
cmp dx,cx
jnc sound2 ; trap zero/overflow
mov ax,34ddh
div cx
mov cx,ax
in al,61h
or al,3 ; enable spkr
iodelay
out 61h,al
mov al,0b6h ; set mode 3
out 43h,al
mov al,cl
iodelay
out 42h,al
mov al,ch
iodelay
out 42h,al
sound2: pop cx
call ms1
in al,61h
and al,0fch ; disable spkr
iodelay
out 61h,al
ret
; MS ( ms -- )
hdr 1,'MS'
ms: call aexec
dw ms0
; SOUND ( freq ms -- )
hdr 1,'SOUND'
sound: call aexec
dw sound0
; BEEP ( -- )
hdr 1,'BEEP'
beep: call aexec
dw beep0
; AT-XY ( x y -- ) position cursor at col x, row y
hdr 1,'AT-XY' ; not bounds checked - allows any
atxy: pop ax ; BIOS permissible value
pop dx
mov dh,al
add dl,wmin
add dh,wmin+1
atxy1: call scurs
nextt
; GET-XY ( -- x y ) get cursor position col x, row y
hdr 1,'GET-XY'
getxy: call gcurs
sub dl,wmin
sub dh,wmin+1
getxy1: sub ax,ax
xchg al,dh
jmp dpush
; SET-WINDOW ( x1 y1 x2 y2 -- )
hdr 1,'SET-WINDOW'
setwin: pop ax
pop cx
mov ch,al
pop ax
pop dx
mov dh,al
mov word ptr wmin,dx
mov word ptr wmax,cx
jmp atxy1
; GET-WINDOW ( -- x1 y1 x2 y2 )
hdr 1,'GET-WINDOW'
getwin: mov dx,word ptr wmin
sub ax,ax
xchg al,dh
push dx
push ax
mov dx,word ptr wmax
jmp getxy1
; ATTRIB ( -- addr ) address of video attribute byte
hdr 1,'ATTRIB'
attrib: call docon
dw cattr
; FOREGROUND ( u -- ) 0-15
hdr 1,'FOREGROUND'
fg: pop ax
and al,0fh
and byte ptr cattr,0f0h
fg1: or cattr,al
nextt
; BACKGROUND ( u -- ) 0-7
hdr 1,'BACKGROUND'
bg: pop ax
and al,7
mov cl,4
shl al,cl
and byte ptr cattr,8fh
jmp fg1
; COLOR-TABLE ( -- addr ) default colors
hdr 1,'COLOR-TABLE'
clrtbl: call docre
dnorm db 07h ; normal
dinver db 70h ; inverse
dbold db 03h ; bold
dbrite db 0Bh ; bright
; NORMAL ( -- )
hdr 1,'NORMAL'
vnorm: mov al,dnorm
vnorm1: mov cattr,al
nextt
; INVERSE ( -- )
hdr 1,'INVERSE'
vinver: mov al,dinver
jmp vnorm1
; BOLD ( -- )
hdr 1,'BOLD'
vbold: mov al,dbold
jmp vnorm1
; BRIGHT ( -- )
hdr 1,'BRIGHT'
vbrite: mov al,dbrite
jmp vnorm1
; CLEAR-LINE ( -- )
hdr 1,'CLEAR-LINE'
cleol: call gcurs
mov ax,0600h
mov cx,dx
mov dl,wmax
cleol1: call videoa
nextt
; INSERT-LINE ( -- )
hdr 1,'INSERT-LINE'
insln: mov ax,0701h
insln1: push ax
call gcurs
pop ax
mov ch,dh
mov cl,wmin
mov dx,word ptr wmax
jmp cleol1
; DELETE-LINE ( -- )
hdr 1,'DELETE-LINE'
delln: mov ax,0601h
jmp insln1
; PAUSE ( -- )
hdr 1,'PAUSE' ; multitasking support
pause: call aexec
pause1 dw 0 ; patched by COLD
; bios console key test (AL)
cseg
bconq: cmp byte ptr kbpend,0
jnz bconq1
mov ah,kbfn+1
int 16h
bconq1: mov al,0
jz bconq2
dec al
bconq2: ret
; dos console key test (AL)
cseg
dconq: mov ah,0bh
int 21h
ret
; bios console in (AL)
cseg
bconi: sub al,al
xchg al,kbpend
or al,al
jnz bconi2
mov ah,kbfn
int 16h
or al,al
jz bconi1
cmp al,80h ; needed when using
jc bconi2 ; INT16 AH=10h
sub al,al ;
bconi1: mov kbpend,ah
or ah,ah
jnz bconi2
mov al,3
bconi2: ret
; dos console in (AL)
cseg
dconi: mov ah,8 ; allow ctl-C/Break
int 21h
ret
; dos console out (AL)
cseg
dcono: mov ah,2 ; allow ctl-C/Break
mov dl,al
int 21h
ret
; bios console out (AL)
cseg
bcono: push ax
call gcurs
pop ax
cmp al,bel ; BEL
jz bcono3
cmp al,bs
jz bcono5
cmp al,cr ; CR
jz bcono4
cmp al,lf ; LF
jz bcono1
cmp al,tab ; TAB
jz bcono6
mov ah,9
mov bl,cattr
mov cx,1
push dx
call videop
pop dx
inc dl
cmp dl,wmax
jna bcono2
mov dl,wmin
bcono1: inc dh
cmp dh,wmax+1
jna bcono2
dec dh
push cx
push dx
mov ax,0601h
mov cx,word ptr wmin
mov dx,word ptr wmax
call videoa
pop dx
pop cx
bcono2: jmp scurs
bcono3: mov ah,0eh
call videop
jmp bcono2
bcono4: mov dl,wmin
bcono5: cmp dl,wmin
jz bcono2
dec dl
jmp bcono2
bcono6: sub dl,wmin
and dl,7
mov al,8
sub al,dl
bcono7: push ax
mov al,20h
call bcono
pop ax
dec al
jnz bcono7
jmp bcono2
cseg
iofn dw biosfn
biosfn dw bconq ; bios functions
dw bconi
dw bcono
dosfn dw dconq ; dos functions
dw dconi
dw dcono
; BIOS-IO ( -- ) use BIOS for I/O calls
hdr 1,'BIOS-IO'
biosio: mov ax,offset biosfn
biosio1:mov iofn,ax
mov byte ptr kbpend,0
nextt
; DOS-IO ( -- ) use DOS for I/O calls
hdr 1,'DOS-IO'
dosio: mov ax,offset dosfn
jmp biosio1
; ?terminal ( -- flag )
hdr x,'?TERMINAL'
qterm: mov bx,iofn
call [bx]
cbw
jmp apush
; KEY? ( -- flag ) (vkeyq) @execute pause
hdr 1,'KEY?'
keyq: call docol
dw lit,vkeyq
dw aexec
dw pause
dw exit
; pckey ( -- char )
hdr x,'PCKEY'
pckey: mov bx,iofn
call [bx+cw]
sub ah,ah
jmp apush
; conin ( -- char ) begin key? until pckey dup 0=
; if drop pckey 128 + then
hdr x,'CONIN'
conin: call docol
conin1 dw keyq
dw zbran,conin1
dw pckey
dw dupp,zequ
dw zbran,conin2
dw drop
dw pckey
dw clit
db 128
dw plus
conin2 dw exit
; KEY ( -- char ) (vkey) @execute pause
hdr 1,'KEY'
key: call docol
dw lit,vkey
dw aexec
dw pause
dw exit
; cls ( -- ) home cursor and clear-screen sequence
cseg
cls: mov ax,0600h
mov cx,word ptr wmin
push cx
mov dx,word ptr wmax
call videoa
pop dx
call scurs
nextt
; conout ( char -- )
hdr x,'CONOUT'
conout: pop ax
cmp al,ff ; FF
jz cls
mov bx,iofn
call [bx+cw*2]
nextt
; lstout ( char -- )
hdr x,'LSTOUT'
lstout: pop dx
mov ah,5
int 21h
nextt
; PAGE ( -- ) 12 emit
hdr 1,'PAGE'
pagee: mov al,ff ; formfeed char
ignore2
; SPACE ( -- ) 32 emit
hdr 1,'SPACE'
space: mov al,20h
sub ah,ah
push ax
; jmp emit
; EMIT ( char -- ) (vemit) @execute 1 out +! pause
hdr 1,'EMIT'
emit: call docol
dw lit,vemit
dw aexec
dw one,outt,pstor
dw pause
dw exit
; TYPE ( c-addr n -- ) 0max 0 ?do count emit loop drop
hdr 1,'TYPE'
typee: call docol
dw zmax,zero
dw xqdo,typee2
typee1 dw count,emit
dw xloop,typee1
typee2 dw drop
dw exit
; SPACES ( n -- ) 0max 0 ?do space loop
hdr 1,'SPACES'
spacs: call docol
dw zmax,zero
dw xqdo,spacs2
spacs1 dw space
dw xloop,spacs1
spacs2 dw exit
; EOL ( -- c-addr u ) ' count build EOL 2 c, $0D c, $0A c, 0 c,
hdr 1,'EOL'
eol: call count
db 2,cr,lf,0
; CR ( -- ) eol type out off
hdr 1,'CR'
crr: call docol
dw eol,typee
dw outt,off
dw exit
; CONSOLE ( -- ) (vcon) @ (vemit) !
hdr 1,'CONSOLE' ; set EMIT to terminal
consol: mov ax,vcon
mov vemit,ax
nextt
; PRINTER ( -- ) (vlst) @ (vemit) !
hdr 1,'PRINTER' ; set EMIT to printer
prnt: mov ax,vlst
mov vemit,ax
nextt
; UPCASE ( char1 -- char2 )
hdr 1,'UPCASE' ; make char uppercase
upcas: pop ax
call upc
jmp apush
; UPPER ( c-addr u -- )
hdr 1,'UPPER' ; make string uppercase
upper: pop cx
pop bx
jcxz upper2
upper1: mov al,[bx]
call upc
mov [bx],al
inc bx
loop upper1
upper2: nextt
; CONTEXT ( -- addr )
hdr 1,'CONTEXT',,1
cont: call docre
acont dw ? ; context
acurr dw ? ; current
dw forth1 ; forth
; get-context ( -- wid )
hdr x,'GET-CONTEXT',,1
getcon: push acont
nextt
; GET-CURRENT ( -- wid )
hdr 1,'GET-CURRENT',,1
getcur: push acurr
nextt
; SET-CURRENT ( wid -- )
hdr 1,'SET-CURRENT',,1
setcur: pop acurr
nextt
; wfind ( c-addr wid -- 0 | xt nfa -1 | xt nfa 1 )
hdr x,'WFIND',,1
wfind: pop bx
pop di
or bx,bx ; wid=0
jz wfind5
mov al,[di]
inc di
mov dx,di
cmp al,31+1 ; in range?
jnc wfind5
or al,al
jz wfind5
sub ch,ch
mov bx,[bx]
mov es,hseg1
wfind1: mov bx,es:[bx]
or bx,bx ; end of list?
jz wfind5
mov di,bx
mov ah,es:[bx] ; nfa
inc bx
mov cl,ah
and cl,31 ; word length
cmp cl,al
jz wfind3
wfind2: add bx,cx ; move to link
jmp wfind1
wfind3: test ah,20h ; smudged?
jnz wfind2
push si
push di
mov si,dx
mov di,bx
if ucase
call cmpnc
else
rep cmpsb
endif
mov cl,al
pop di
pop si
jnz wfind2
add bx,cx
push es:[bx+cw] ; xt
push di ; nfa
and ah,40h ; immediate?
jnz wfind4
jmp true
wfind4: jmp one
wfind5: jmp zero
; (find) ( c-addr -- c-addr 0 | xt -1 | xt 1 )
; 0 3 0 ?do over i cells context + @
; wfind ?dup if nip 2nip leave then loop
hdr x,'(FIND)',,1
pfind: call docol
dw zero
dw three
dw zero
dw xqdo,pfind3
pfind1 dw over
dw ido,cells
dw cont
dw plus,at
dw wfind,qdup
dw zbran,pfind2
dw nip,tnip
dw pleav,pfind1-cw
pfind2 dw xloop,pfind1
pfind3 dw exit
; FIND ( c-addr -- c-addr 0 | xt -1 | xt 1 )
hdr 1,'FIND',,1
find: call aexec
dw pfind
if 0
; SEARCH-WORDLIST ( c-addr u wid -- 0 | xt -1 | xt 1 )
; >r wpack r> wfind dup if nip then
hdr 1,'SEARCH-WORDLIST',,1
swlis: call docol
dw tor
dw wpack
dw fromr
dw wfind
dw dupp
dw zbran,swlis1
dw nip
swlis1 dw exit
endif
if wopt
; -? ( -- ) warning @ 0fffe and warning !
hdr 1,'-?',,1 ; disable warnings for next definition only
dques: and byte ptr warnn1,0feh ; clear bit 0
nextt
; warning? ( -- 0|1 ) warning @ dup if 1 and $7FFF over 0<> or
; warning ! then
hdr x,'WARNING?',,1 ; get warning flag and apply mask
qwarn: call docol
dw warnn,at
dw dupp
dw zbran,qwarn1
dw one,andd ; test redefinition warning
dw lit,7fffh ; disable system warning
dw over,zneq ; else enable all warnings
dw orr
dw warnn,store
qwarn1 dw exit
endif
; header ( xt|0 "name" -- )
; warning? 2>r dph @ (hm-64) u>
; abort" no name space" cseg bl-word dup
; c@ 32 1 within abort" invalid name" dup
; find nip r> and if over count type
; ." is redefined " then hseg over count
; tuck + get-current w>name over ! cell+
; swap 5 + dph @ over dph +! dup get-current
; @ h! rot r> ?dup 0= if here then dup rot !
; over last 2! swap cmovel
hdr x,'HEADER',,1
headr: call docol
if wopt
dw qwarn
else
dw warnn,at
endif
dw ttor
dw dph,at
dw lit,hm-64
dw ugrea
dw pabq
dcs 'no name space'
dw csegg
dw blword
dw dupp,cat
dw clit
db 32
dw one,within
dw pabq
dcs 'invalid name'
dw dupp,find,nip
dw fromr,andd
dw zbran,headr1
dw dupp,count,typee
dw pdotq
dcs ' is redefined '
headr1 dw hseg
dw over,count
dw tuck
dw plus
dw getcur,wtnam
dw over,store
dw cellp,swap
dw clit
db 5
dw plus
dw dph,at
dw over,dph,pstor
dw dupp
dw getcur
dw at,hstor ; MS-DOS version
dw rot
dw fromr,qdup,zequ
dw zbran,headr2
dw here
headr2 dw dupp,rot,store
dw over,last,tstor
dw swap,cmovl
dw exit
; ,call ( addr -- ) $E8 c, here 2+ - ,
hdr x,',CALL',,1
comcall:call docol
dw clit
db 0e8h ; 'call' opcode
dw ccomm
dw here,twop,subb ; relative for 8086
dw comma
dw exit
; CREATE ( -- addr ) 'next build
hdr 1,'CREATE',,1
creat: push tnext1
; jmp build
docre equ next
; BUILD ( xt "name" -- ) 0 header ,call
hdr 1,'BUILD',,1
build: call docol
dw zero,headr
dw comcall
dw exit
; : ( -- ) (docol) build smudge bal off sp@ dup
; csp 2! ]
hdr 1,':',,1
colon: call docol
dw lit,docol
dw build
dw smudg
colon1 dw bal,off
dw spat,dupp
dw cspp,tstor
dw rbrac
dw exit
; ; ( -- ) postpone exit bal @ ?bal ?csp smudge
; postpone [ ;immediate
hdr 1,';',1,1
semic: call docol
dw comp,exit
dw bal,at
dw qbal
dw qcsp
dw smudg
dw lbrac
dw exit
; :NONAME ( -- xt ) warning? drop here dup (dnfa) last 2!
; (docol) ,call bal off sp@ dup csp 2! ]
hdr 1,':NONAME',,1
nonam: call docol
if wopt
dw qwarn,drop ; allow -?
endif
dw here
dw dupp ; allow RECURSE
dw lit,dnfa-horig ; allow IMMEDIATE
dw last,tstor
dw lit,docol
dw comcall
dw bran,colon1
; (;CODE) last cell+ @ 1+ r> over 2+ - swap !
hdr 1,'(;CODE)',,1
pscod: mov bx,last2
inc bx
sub si,bx ; relative for 8086
dec si ;
dec si ;
mov [bx],si
jmp exit
; DOES> postpone (;code) (docol) ,call ;immediate
hdr 1,'DOES>',1,1
does: call docol
dw comp,pscod
dw lit,docol
dw comcall
dw exit
; VARIABLE ( -- addr ) create 2 allot
hdr 1,'VARIABLE',,1
var: call docol
dw creat
dw two,allot
dw exit
; VALUE ( -- x ) (doval) build ,
hdr 1,'VALUE',,1
value: call docol
value1 dw lit,doval
dw build
dw comma
dw exit
doval equ at
; CONSTANT ( -- x ) char? if (docco) build c,
; else value then
hdr 1,'CONSTANT',,1
con: call docol
dw charq
dw zbran,value1
dw lit,docco
dw build
dw ccomm
dw exit
docon equ at
docco equ cat
; 2VARIABLE ( -- addr ) create 4 allot
hdr 1,'2VARIABLE',,1
tvar: call docol
dw creat
dw clit
db 4
dw allot
dw exit
dotvar equ next
; 2CONSTANT ( -- x2 x1 ) (dotcon) build , ,
hdr 1,'2CONSTANT',,1
tcon: call docol
dw lit,dotcon
dw build
dw comma,comma
dw exit
dotcon equ tat
; USER ( -- addr ) (douse) build ,
hdr 1,'USER',,1 ; FIG
user: call docol
dw lit,douse
dw build
dw comma
dw exit
; ADDR ( -- addr ) ' >body state? if postpone literal then
; ;immediate
hdr 1,'ADDR',1,1 ; state-smart
addr: call docol
dw tick,tbody
dw stateq
dw zbran,addr1
dw liter
addr1 dw exit
; (to) ( x -- ) r> dup cell+ >r @ >body !
hdr x,'(TO)'
pto: lodsw
mov bx,ax
pop [bx+3]
nextt
; TO ' state? if postpone (to) , else >body !
; then ;immediate
hdr 1,'TO',1,1 ; state-smart
to: call docol
dw tick
dw stateq
dw zbran,to1
dw comp,pto
dw comma
dw bran,to2
to1 dw tbody,store
to2 dw exit
cseg
undef: call docol
dw one
dw pabq
dcs 'uninitiated DEFER'
; DEFER ( -- ) ['] @execute build (undef) ,
hdr 1,'DEFER',,1
defer: call docol
dw lit,aexec
dw build
dw lit,undef
dw comma
dw exit
; IS aka to is
hdr 1,'IS',1,,to ; state-smart
is equ to
pis equ pto
; AKA ( "oldname" "newname" -- ) defined tuck ?defined header
; $80 xnfa 0> if immediate then
hdr 1,'AKA',,1
aka: call docol
dw defined
dw tuck,qdef
dw headr ; equivalent of
dw clit ; ALIAS ( xt "newname" -- )
db 80h ;
dw xnfa ;
dw zgrea
dw zbran,aka1
dw immed
aka1 dw exit
; Constants
; TRUE ( -- -1 )
hdr 1,'TRUE'
true: mov ax,-1
push ax
nextt
; FALSE ( -- 0 )
hdr 1,'FALSE'
false: sub ax,ax
push ax
nextt
; -1 ( -- -1 ) aka true -1
hdr 1,'-1',,,true
; 0 ( -- 0 ) aka false 0
hdr 1,'0',,,false
zero equ false
; 1 ( -- 1 )
hdr 1,'1'
one: call docco
db 1
; 2 ( -- 2 )
hdr 1,'2'
two: call docco
db 2
; 3 ( -- 3 )
hdr 1,'3'
three: call docco
db 3
; BL ( -- 32 ) ascii value for space character
hdr 1,'BL'
bll: call docco
db 32
; B/BUF ( -- u ) bytes per screen buffer
hdr 1,'B/BUF',,1 ; FIG
bbuf: call doval
bbuf1 dw 128*8 ; default
; C/L ( -- u ) chars per screen line
hdr 1,'C/L',,1 ; FIG
csll: call doval
dw 64 ; default
; For applications, LIMIT is the upper limit of available memory.
; In forth, it is the beginning of the area which holds the screen
; file buffer, word headers and system definitions.
; LIMIT ( -- addr )
hdr 1,'LIMIT' ; FIG
limit: call docon ; application word - used by COLD
limit1 dw ? ; patched on startup
; HLIMIT ( -- addr )
hdr 1,'HLIMIT',,1 ; upper limit of heads memory
hlimit: call docon
dw hm
; 'NEXT ( -- addr ) address of NEXT
hdr 1,"'NEXT"
tnext: call docon
tnext1 dw next
; SYS-VEC ( -- addr ) system vector table
hdr 1,'SYS-VEC'
sysvec: call docre
vkeyq dw qterm ; 0 KEY?
vkey dw conin ; 2 KEY
vemit dw conout ; 4 EMIT
vcon dw conout ; 6 CONSOLE out
vlst dw lstout ; 8 PRINTER out
ainit dw pinit ; 10 INIT patch
aident dw piden ; 12 IDENTIFY patch
afnumb dw pfnum ; 14 FNUMBER patch
nfps dw fps ; 16 fp-stack size (bytes)
anumb dw pnumb ; 18 NUMBER? patch
nfpm dw fnum*fw ; 20 fp-stack min (bytes)
nrts dw rts ; 22 return stack (bytes)
nus dw us ; 24 user area (bytes)
npno dw pno ; 26 HOLD buffer size (bytes)
nmscon dw -2386 ; 28 MS timing constant
ntmode dw 3 ; 30 Timer 0 mode
; Variables
; UP ( -- addr ) user area pointer
hdr 1,'UP'
up: call docre
upp dw ?
; FSP ( -- addr ) fp stack pointer
hdr 1,'FSP'
fsp: call docre
fspp dw ?
; boot ( -- addr ) boot word (holds forth/application xt)
hdr x,'BOOT'
boot: call docre
boot1 dw 0 ; xt
boot2 dw 0 ; 0=forth
; SYS ( -- addr ) compile to system or application
hdr 1,'SYS'
sys: call docre ; application word - used by HERE UNUSED
sys1 dw 0
; LAST ( -- addr ) occupies 2 cells
hdr 1,'LAST',,1
last: call docre
last1 dw topnfa ; latest nfa
last2 dw topxt ; latest xt
; BLK
hdr 1,'BLK',,1
blk: call docre
blk1 dw ?
; >IN
hdr 1,'>IN',,1
inn: call docre
inn1 dw ?
; 'SOURCE occupies 2 cells
hdr 1,'''SOURCE',,1
tsourc: call docre
tsour1 dw ?,?
; STATE
hdr 1,'STATE',,1
state: call docre
state1 dw ?
; SCR ( -- addr ) occupies 2 cells
hdr 1,'SCR',,1
scr: call docre
dw ?,? ; screen number, offset
; WARNING
hdr 1,'WARNING',,1 ; FIG
warnn: call docre
warnn1 dw ?
; CSP ( -- addr ) occupies 2 cells
hdr 1,'CSP',,1 ; FIG
cspp: call docre
cspp1 dw ? ; current stack pointer
cfz1 dw ? ; control flow stack base
; CHECKING
hdr 1,'CHECKING',,1
check: call docre
check1 dw ?
; errmsg ( -- addr ) message holder for abort"
hdr x,'ERRMSG'
errmsg: call docre
dw ?,?
; zbuf ( -- addr ) filename buffer pointers
hdr x,'ZBUF'
zbuf: call docre
zbuf1 dw zb1 ; next buffer
dw zb2 ; last buffer
; User Variables
; bytes 0-5 reserved for multitasking
; S0
hdr 1,'S0' ; FIG
szero: call douse
dw 6
; R0
hdr 1,'R0' ; FIG
rzero: call douse
dw 8
; DP application dictionary pointer
hdr 1,'DP' ; FIG
dpp: call douse
dw 10
; dps system dictionary pointer
hdr x,'DPS',,1 ; must follow DP
dps: call douse
dw 12
; VOC-LINK
hdr 1,'VOC-LINK',,1 ; FIG
vocl: call douse
dw 14
; FS0
hdr 1,'FS0'
fszero: call douse
dw 16
; DPH ( -- addr ) heads dictionary pointer
hdr 1,'DPH',,1
dph: call douse
dw 18
; End of boot-up literals
; bytes 20-21 reserved for locals
; CATCHER
hdr 1,'CATCHER'
catchr: call douse
dw 22
; BASE
hdr 1,'BASE'
base: call douse
dw 24
; hld
hdr x,'HLD' ; FIG
hld: call douse
dw 26
; DPL
hdr 1,'DPL' ; FIG
dpl: call douse
dw 28
; OUT
hdr 1,'OUT' ; FIG
outt: call douse
dw 30
; User area bytes #USER onwards are available for user applications
; #USER ( -- +n )
hdr 1,'#USER',,1
nusr: call doval
dw 32
; sys? ( -- flag ) sys @ 0<>
hdr x,'SYS?'
sysq: push word ptr sys1
jmp zneq
; state? ( -- flag ) state @ 0<>
hdr x,'STATE?',,1
stateq: push word ptr state1
jmp zneq
; check? ( -- flag ) checking @ 0<>
hdr x,'CHECK?',,1
chkq: push word ptr check1
jmp zneq
; APPLICATION ( -- ) sys off
hdr 1,'APPLICATION'
app: mov bx,offset sys1
jmp off1
; SYSTEM ( -- ) sys on
hdr 1,'SYSTEM',,1
system: mov bx,offset sys1
jmp on1
; h ( -- addr ) sys @ if dps else dp then
hdr x,'H'
hh: mov ax,sys1
or ax,ax
jnz hh1
jmp dpp
hh1: jmp dps
; HERE ( -- addr ) h @
hdr 1,'HERE'
here: call docol
dw hh,at
dw exit
; ALLOT ( u -- ) here over dup unused u>
; abort" no data space" erase h +!
hdr 1,'ALLOT' ; non-standard
allot: call docol
dw here,over
dw dupp,unus,ugrea
dw pabq
dcs 'no data space'
dw erase
allot1 dw hh,pstor
dw exit
; -ALLOT ( u -- ) negate h +!
hdr 1,'-ALLOT'
dallot: call docol
dw negat
dw bran,allot1
; C, ( char -- ) here 1 allot c!
hdr 1,'C,',,1
ccomm: call docol
dw here
dw one,allot
dw cstor
dw exit
; , ( x -- ) here 2 allot !
hdr 1,',',,1
comma: call docol
dw here
dw two,allot
dw store
dw exit
; >BODY ( xt -- addr ) 3 +
hdr 1,'>BODY'
tbody: pop ax
add ax,3
jmp apush
; body> ( addr -- xt ) 3 -
;
; hdr x,'BODY>'
;fbody: pop ax
; sub ax,3
; jmp apush
; n>count ( nfa -- h-addr len ) dup 1+ swap hc@ 31 and
hdr x,'N>COUNT',,1
ncnt: pop bx
mov es,hseg1
mov al,es:[bx]
inc bx
push bx
and ax,31
jmp apush
; n>link ( nfa -- lfa ) n>count +
hdr x,'N>LINK',,1
nlnk: call docol
dw ncnt,plus
dw exit
; N>NAME ( nfa1 -- nfa2 | 0 ) n>link h@
hdr 1,'N>NAME',,1
ntnam: call docol
dw nlnk,hat
dw exit
; name> ( nfa -- xt ) n>link cell+ h@
hdr x,'NAME>',,1
namef: call docol
dw nlnk,cellp
dw hat
dw exit
; W>NAME ( wid -- nfa | 0 ) @ h@
hdr 1,'W>NAME',,1
wtnam: pop bx
push [bx]
jmp hat
; -alias ( nfa -- nfa flag ) dup hc@ $80 <
hdr x,'-ALIAS',,1 ; false if alias
dalias: call docol
dw dupp,hcat
dw clit
db 80h
dw less
dw exit
; >name ( xt -- nfa | 0 )
; voc-link begin @ dup while tuck cell- w>name
; begin ?dup while -alias if 2dup name> = if
; -rot 2drop end then n>name repeat swap
; repeat nip
hdr x,'>NAME',,1
tnam: call docol
dw vocl
tnam1 dw at
dw dupp
dw zbran,tnam5
dw tuck
dw cellm
dw wtnam
tnam2 dw qdup
dw zbran,tnam4
dw dalias ; skip if alias
dw zbran,tnam3
dw tdup,namef
dw equal
dw zbran,tnam3
dw drot,tdrop
dw exit
tnam3 dw ntnam
dw bran,tnam2
tnam4 dw swap
dw bran,tnam1
tnam5 dw nip
dw exit ; not found
; (NAME) ( nfa -- c-addr u ) n>count <# begin dup while
; 1- 2dup + hc@ hold repeat #>
hdr 1,'(NAME)',,1
pname: call docol
dw ncnt
dw bdigs
pname1 dw dupp
dw zbran,pname2
dw onem
dw tdup,plus,hcat
dw hold
dw bran,pname1
pname2 dw edigs
dw exit
; .ID ( nfa | 0 -- ) ?dup if dup name> limit u< if (dnorm) else
; (dbold) then c@ over hc@ $40 and 3 rshift
; xor attrib c! (name) type normal end
; ." [noname]"
hdr 1,'.ID',,1
dotid: call docol
dw qdup
dw zbran,dotid3
dw dupp,namef
dw limit,uless
dw zbran,dotid1
dw lit,dnorm ; normal
dw bran,dotid2
dotid1 dw lit,dbold ; bold
dotid2 dw cat
dw over,hcat
dw clit ; immediate?
db 40h
dw andd
dw three,rsh
dw xorr ; toggle bright
dw attrib,cstor
dw pname,typee
dw vnorm
dw exit
dotid3 dw pdotq
dcs '[noname]'
dw exit
; .NAME ( xt -- ) >name .id
hdr 1,'.NAME',,1
dotnam: call docol
dw tnam,dotid
dw exit
; .VOC ( wid -- ) cell+ cell+ @ .id
hdr 1,'.VOC',,1
dotvoc: pop bx
add bx,cw*2
push [bx]
jmp dotid
; !CSP ( -- ) sp@ csp !
hdr 1,'!CSP',,1 ; FIG
scsp: mov ax,sp
mov cspp1,ax
nextt
; ?CSP ( -- ) sp@ csp @ - ?bal
hdr 1,'?CSP',,1 ; FIG
qcsp: mov ax,cspp1
sub ax,sp
push ax
jmp qbal
; ?COMP ( -- ) state? 0= abort" compilation only"
hdr 1,'?COMP',,1 ; FIG
qcomp: call docol
dw stateq
dw zequ
dw pabq
dcs 'compilation only'
dw exit
; ?EXEC ( -- ) state? abort" execution only"
hdr 1,'?EXEC',,1 ; FIG
qexec: call docol
dw stateq
dw pabq
dcs 'execution only'
dw exit
; ?STACK ( -- ) sp@ s0 @ 1+ pad within abort" stack?"
; rp@ r0 @ 1+ fs0 @ within abort" r-stack?"
; fsp @ fs0 @ dup 1+ swap (nfpm) @ - within
; abort" f-stack?"
hdr 1,'?STACK',,1 ; FIG
qstac: call docol
dw spat
dw szero,at
dw onep
dw pad
dw within
dw pabq
dcs 'stack?'
dw rpat
dw rzero,at
dw onep
dw fszero,at ; = S0 if no float
dw within
dw pabq
dcs 'r-stack?'
dw fsp,at
dw fszero,at
dw dupp,onep,swap
dw lit,nfpm
dw at
dw subb
dw within
dw pabq
dcs 'f-stack?'
dw exit
; ?defined ( flag -- ) 0= abort" is undefined"
hdr x,'?DEFINED',,1
qdef: call docol
dw zequ
dw pabq
dcs 'is undefined'
dw exit
; [ state off ;immediate
hdr 1,'[',1,1
lbrac: mov bx,offset state1
jmp off1
; ] state on
hdr 1,']',,1
rbrac: mov bx,offset state1 ; must be -1 for INTERPRET to work
jmp on1
; (ACCEPT) ( c-addr +n1 -- +n2)
; 0 begin key dup >r dup bl 127 within 2over -
; and if dup emit over 4 pick + c! 1+ else 2dup
; dup 8 = swap esc = or and if esc = if 0 swap
; else 1- 1 then begin 8 dup emit space emit 1-
; dup 0= until then drop then r> 13 = until
; -rot 2drop
hdr x,'(ACCEPT)'
pacce: call docol
dw zero
pacce1 dw key
dw dupp,tor
dw dupp,bll ; only accept chars between 32 and 126
dw clit
db 127
dw within
dw tover,subb
dw andd
dw zbran,pacce2
dw dupp,emit
dw over
dw clit
db 4
dw pick
dw plus
dw cstor
dw onep
dw bran,pacce6
pacce2 dw tdup
dw dupp
dw clit
db bs ; backspace?
dw equal,swap
dw clit
db escape ; escape?
dw equal,orr
dw andd
dw zbran,pacce5
dw clit
db escape ; escape?
dw equal
dw zbran,pacce3
dw zero,swap
dw bran,pacce4
pacce3 dw onem,one
pacce4 dw clit
db bs
dw dupp,emit
dw space,emit
dw onem
dw dupp,zequ
dw zbran,pacce4
pacce5 dw drop
pacce6 dw fromr
dw clit
db cr ; cr?
dw equal
dw zbran,pacce1
dw drot,tdrop
dw exit
; ACCEPT ( c-addr +n1 -- +n2)
hdr 1,'ACCEPT'
accept: call aexec
dw pacce
; PAD ( -- addr ) dp @ (npno) @ +
hdr 1,'PAD'
pad: mov bx,upp
mov ax,[bx+10] ; DP
add ax,npno
jmp apush
; SOURCE ( -- c-addr u ) 'source 2@
hdr 1,'SOURCE',,1
source: mov bx,offset tsour1
jmp tat1
; PARSE ( char -- c-addr u ) 0 (parse)
hdr 1,'PARSE',,1
parse: sub ax,ax
push ax
; jmp ppars
; (parse) ( char f -- c-addr u ) 2>r source >in @ /string r> if tuck
; r@ skip over - >in +! then 2dup r>
; scan nip tuck - dup rot 0<> - >in +!
hdr 0,'(PARSE)',,1
ppars: call docol
dw ttor
dw source
dw inn,at,sstr
dw fromr
dw zbran,ppars1
dw tuck
dw rat,skip
dw rot,over,subb
dw inn,pstor
ppars1 dw tdup
dw fromr
dw scan,nip
dw tuck
dw subb,dupp
dw rot,zneq
dw subb
dw inn,pstor
dw exit
; +psb ( a1 n1 n2 -- n3 ) >r (pssiz) r@ - umin r> 2dup + >r
; (psb) + swap cmove r>
hdr x,'+PSB',,1
ppsb: pop bx
pop cx
mov di,pssiz
sub di,bx
cmp di,cx
jnc ppsb1
mov cx,di
ppsb1: mov di,offset orig+psb
add di,bx
add bx,cx
pop ax
push bx
jmp cmove1
; /PARSE ( char "ccc" -- a n ) 0 begin >r dup parse 2dup r> +psb >r
; 1+ + dup source + u< while 2dup c@ =
; while 1 dup >in +! r> +psb repeat
; then 2drop (psb) r>
hdr 1,'/PARSE',,1
spars: call docol
dw zero
spars1 dw tor
dw dupp,parse
dw tdup
dw fromr,ppsb
dw tor
dw onep,plus
dw dupp
dw source,plus
dw uless
dw zbran,spars2
dw tdup,cat
dw equal
dw zbran,spars2
dw one,dupp
dw inn,pstor
dw fromr,ppsb
dw bran,spars1
spars2 dw tdrop
dw lit,psb
dw fromr
dw exit
; pwa ( -- adr ) parsed word address
hdr x,'PWA',,1
pwa: call doval
dw ?
; wpack ( c-addr1 u -- c-addr2 )
; 255 umin (em-5) over 31 max - dup to pwa
; pack bl affix
hdr x,'WPACK',,1 ; pack string into WORD's buffer
wpack: call docol
dw clit
db 255
dw umin
if retro
dw here
else
dw lit,em-5
dw over
dw clit ; word buffer 31+5 chars min (F94)
db 31
dw max
dw subb
endif
dw dupp
dw pto,pwa
dw pack
dw bll,affix ; trailing blank
dw exit
; bl-word ( -- c-addr ) bl word
hdr x,'BL-WORD',,1
blword: mov ax,20h
push ax
; jmp wordd
; WORD ( char -- c-addr ) true (parse) wpack
hdr 1,'WORD',,1
wordd: call docol
dw true,ppars
dw wpack
dw exit
; TOKEN ( -- c-addr u ) bl-word count
hdr 1,'TOKEN',,1
token: call docol
dw blword,count
dw exit
; defined ( -- c-addr 0 | xt -1 | xt 1 ) bl-word find
hdr x,'DEFINED',,1
defined:call docol
dw blword,find
dw exit
; ' ( -- xt ) defined ?defined
hdr 1,'''',,1
tick: call docol
dw defined
dw qdef
dw exit
; [UNDEFINED] ( -- flag ) defined nip 0= ;immediate
hdr 1,'[UNDEFINED]',1,1
budef: call docol
dw defined
dw nip
dw zequ
dw exit
; [DEFINED] ( -- flag ) postpone [undefined] 0= ;immediate
hdr 1,'[DEFINED]',1,1
bdef: call docol
dw budef,zequ
dw exit
; IMMEDIATE ( -- ) $40 xnfa
hdr 1,'IMMEDIATE',,1
immed: mov dl,40h
ignore1
; xnfa ( x -- ) toggle nfa bit
xnfa: pop dx
mov bx,last1
mov es,hseg1
xor es:[bx],dl
nextt
; SMUDGE ( -- ) $20 xnfa
hdr 1,'SMUDGE',,1 ; FIG
smudg: mov dl,20h
jmp xnfa+1
; \ ( "ccc" -- ) source blk @ if c/l >in @ over / 1+ *
; min then >in ! drop ;immediate
hdr 1,'\',1,1
bslas: call docol
dw source
dw blk,at
dw zbran,bslas1
dw csll
dw inn,at
dw over,slash
dw onep,star
dw min
bslas1 dw inn,store
dw drop
dw exit
; \\ ( "ccc" -- ) source >in ! drop ;immediate
hdr 1,'\\',1,1
bslss: call docol
dw source
dw bran,bslas1
; ( ( "ccc<delim>" ) [char] ) parse 2drop ;immediate
hdr 1,'(',1,1
paren: call docol
dw clit
db ')'
dw parse,tdrop
dw exit
; .( ( "ccc<delim>" ) [char] ) /parse type ;immediate
hdr 1,'.(',1,1
dotp: call docol
dw clit
db ')'
dw spars
dw typee
dw exit
; LINK, ( a -- ) here over @ , swap !
hdr 1,'LINK,',,1
linkc: call docol
dw here
dw over,at
dw comma
dw swap,store
dw exit
; WORDLIST ( -- wid ) here dph @ $2001 over h! cell+ 0 over h!
; [ 2 cells ] literal dph +! , voc-link link,
; 0 ,
hdr x,'WORDLIST',,1
wlist: call docol
dw here
dw dph,at
dw lit,2001h
dw over,hstor
dw cellp
dw zero ; nfa of top word in vocabulary
dw over,hstor
dw clit
db cw*2
dw dph,pstor
dw comma
dw vocl,linkc ; link in wordlist
dw zero,comma ; null name
dw exit
; VOCABULARY ( "name" ) sys? system wordlist dup value last @
; swap cell+ cell+ ! sys ! does> @ context !
hdr 1,'VOCABULARY',,1
vocab: call docol
dw sysq
dw system
dw wlist
dw dupp,value
dw last,at ; set name field in wordlist struct
dw swap
dw cellp,cellp
dw store
dw sys,store
dw pscod
dovoc: call docol
dw at
dw cont,store
dw exit
; DEFINITIONS ( -- ) get-context set-current
hdr 1,'DEFINITIONS',,1
defin: call docol
dw getcon
dw setcur
dw exit
; wordlist structure
heads segment public
dw 2001h ; dummy nfa for vocab chaining
forth0 dw topnfa ; nfa of top word in vocabulary
heads ends
aseg
forth1 dw forth0-horig ; top word pointer
forth2 dw 0 ; previous vocabulary
dw forth3 ; vocab nfa
; FORTH vocabulary forth
hdr 1,'FORTH',,1
forth: call dovoc
dw forth1 ; address of wid
forth3 = lastl
; UNUSED ( -- u ) sys? if (esm) else s0 then @ here
; 255 + 2dup u> -rot - and
hdr 1,'UNUSED'
unus: call docol
dw sysq
dw zbran,unus1
dw lit,esm
dw bran,unus2
unus1 dw szero
unus2 dw at
dw here
dw clit ; allow margin
db 255
dw plus
dw tdup
dw ugrea
dw drot
dw subb
dw andd
dw exit
; INTERPRET ( -- ) begin bl-word dup c@ while find ?dup if
; state? = if compile, else execute then
; else count base @ >r over c@ case [char] %
; of binary 1 endof [char] $ of hex 1 endof
; [char] # of decimal 1 endof 0 swap endcase
; /string 2dup number? if 2nip dpl @ 0< if
; drop state? if postpone literal then else
; state? if postpone 2literal then then true
; else fnumber then r> base ! ?defined then
; ?stack repeat drop
hdr 1,'INTERPRET',,1
inte: call docol
inte1 dw blword
dw dupp,cat
dw zbran,inte15 ; while not end of input stream
dw find
dw qdup
dw zbran,inte4 ; if found
dw stateq
dw equal
dw zbran,inte2 ; if compiling and not immediate
dw comxt
dw bran,inte3
inte2 dw exec
inte3 dw bran,inte14
inte4 dw count
dw base,at,tor
dw over,cat
dw clit
db '%'
dw pof,inte5
dw bin,one
dw bran,inte8
inte5 dw clit
db '$'
dw pof,inte6
dw hex,one
dw bran,inte8
inte6 dw clit
db '#'
dw pof,inte7
dw decim,one
dw bran,inte8
inte7 dw zero,swap
dw drop
inte8 dw sstr
dw tdup
pnumb equ $
dw numq ; NUMBER? patch
dw zbran,inte12
dw tnip
dw dpl,at,zless
dw zbran,inte10
dw drop
dw stateq
dw zbran,inte9
dw liter
inte9 dw bran,inte11
inte10 dw stateq
dw zbran,inte11
dw tlite
inte11 dw true
dw bran,inte13
inte12 equ $
pfnum equ $
dw fnu ; FNUMBER patch
inte13 dw fromr,base,store
dw qdef
inte14 dw qstac
dw bran,inte1
inte15 dw drop
dw exit
; (eval) ( c-addr u blk -- ) blk @ >in @ 2>r source 2>r blk !
; 'source 2! >in off interpret
; 2r> 'source 2! 2r> >in ! blk !
hdr x,'(EVAL)',,1 ; does not restore block contents
peval: call docol
dw blk,at
dw inn,at
dw ttor
dw source,ttor
dw blk,store
dw tsourc,tstor
dw inn,off ; reset >IN
dw inte
dw tfrom
dw tsourc,tstor
dw tfrom
dw inn,store
dw blk,store
dw exit
; ?BLOCK ( -- ) blk @ dup if block then drop
hdr 1,'?BLOCK',,1 ; reload block
qblock: call docol
dw blk,at
dw dupp
dw zbran,qblock1
dw block
qblock1 dw drop
dw exit
; EVALUATE ( c-addr u -- ) 0 (eval) ?block
hdr 1,'EVALUATE',,1
eval: call docol
dw zero,peval
dw qblock
dw exit
; (refill) ( -- flag ) blk @ ?dup if 1+ dup #screens u< and dup
; while dup blk ! block b/buf else (tib)
; dup 80 accept space then 'source 2! >in
; off true then
hdr x,'(REFILL)',,1 ; doesn't correctly handle source
prefil: call docol ; from EVALUATE
if debug
dw pdotq
dcs '(REFILL) '
endif
dw blk,at
dw qdup
dw zbran,prefil1
dw onep,dupp
dw nscr,uless
dw andd,dupp
dw zbran,prefil3
dw dupp,blk,store
dw block,bbuf
dw bran,prefil2
prefil1 dw lit,tib
dw dupp
dw clit
db 80
dw accept
dw space
prefil2 dw tsourc,tstor
dw inn,off
dw true
prefil3 dw exit
; REFILL ( -- flag )
hdr 1,'REFILL',,1
refil: call aexec
dw prefil
; reset ( -- ) catcher off cseg sseg ! -caps bios-io
; console
hdr x,'RESET'
reset: call docol
dw catchr,off ; reset error handler
dw csegg ; set search segment
dw sseg,store
dw dcaps ; reset COMPARE/SEARCH caps
dw biosio ; default i/o mode
dw consol ; set EMIT vector
dw exit
; /interpret ( -- ) blk off >in off postpone [
hdr x,'/INTERPRET',,1
sinte: sub ax,ax
mov blk1,ax
mov inn1,ax
jmp lbrac
; forth-reset ( -- ) (em) set-limit empty warning on checking
; on (fdbs) (fdsiz*nfd) erase empty-buffers
; /interpret 'source off bl-word drop sp@
; csp cell+ !
hdr x,'FORTH-RESET',,1
freset: call docol
dw lit,em
dw setlim
dw empty ; reset vocabulary pointers
dw warnn,on ; enable warnings
dw check,on ; enable checking
dw lit,fdbs ; clear files
dw lit,fdsiz*nfd ;
dw erase ;
dw mtbuf ; mark screen buffer as empty
dw sinte ; reset interpreter
dw tsourc,off ; clear parsed word buffer
dw blword,drop ;
if cfs
dw spat ; set CF stack base to safe value
dw cspp,cellp
dw store
endif
dw exit
; (quit) ( -- ) r0 @ rp! reset normal /interpret begin
; cr (refill) drop interpret state? 0= if
; ." ok" then again
hdr x,'(QUIT)',,1
pqui: call docol
dw rzero,at
dw rpsto
dw reset
dw vnorm
dw sinte
if debug
dw pdotq
dcs ' QUIT '
endif
pqui1 dw crr
dw prefil,drop
dw inte
dw stateq
dw zequ
dw zbran,pqui2
dw pdotq
dcs ' ok'
pqui2 dw bran,pqui1
; RETURN ( x -- ) exit to DOS with return code x
hdr 1,'RETURN'
retrn: mov al,iattr ; restore video attribute
mov cattr,al
mov al,cr ; force update - this kludge
call bcono ; works if cursor is located
mov al,lf ; on bottom screen row
call bcono
call gmode ; restore video mode
mov ax,word ptr imode
cmp ax,word ptr cmode
jz retrn1
sub ah,ah
int 10h
retrn1: mov dl,defdrv ; restore drive
mov ah,0eh
int 21h
pop ax
mov ah,4Ch
int 21h
; BYE ( -- ) close-all console normal 0 return
hdr 1,'BYE',,1
bye: call docol
dw closa
dw consol
dw vnorm
dw zero,retrn
; boot? ( -- bootword ) (iboot) @
hdr x,'BOOT?'
bootq: mov ax,iboot
jmp apush
; QUIT ( i*x -- i*x ) 0 ?return
hdr 1,'QUIT'
quit: sub ax,ax
push ax
; jmp qret
; ?return ( code -- ) boot? if return then drop (quit)
hdr x,'?RETURN'
qret: call docol
dw bootq
dw zbran,qret1
dw retrn
qret1 dw drop
dw pqui
; (abort) ( -- ) s0 @ sp! fs0 @ fsp ! 1 ?return
hdr x,'(ABORT)'
pabor: call docol
dw szero,at
dw spsto
dw fszero,at
dw fsp,store
if debug
dw pdotq
dcs ' (ABORT) '
endif
dw one,qret
; .error ( -- ) cr blk @ ?dup if screen? and if filename type
; >in @ 2- 0max blk @ 2dup scr 2! ." Scr "
; u. c/l / ." Line " . cr then then ." Error: "
; [char] " dup emit pwa count 31 min type emit
hdr x,'.ERROR',,1
doterr: call docol
dw crr
dw blk,at
dw qdup
dw zbran,doterr1
dw scrnq
dw andd ; screen file open and loading from block?
dw zbran,doterr1
dw loadf,typee
dw inn,at
dw twom ; adjust pointer
dw zmax
dw blk,at
dw tdup ; set error block, offset
dw scr,tstor
dw pdotq
dcs ' Screen '
dw udot
dw csll
dw slash
dw pdotq
dcs 'Line '
dw dot
dw crr
doterr1 dw pdotq
dcs 'Error: '
dw clit
db '"'
dw dupp,emit
dw pwa,count
dw clit
db 31
dw min
dw typee
dw emit
dw exit
; error ( n -- ) -1 of (abort) then -2 of boot cell+ @ 0=
; if .error then space errmsg 2@ type
; (abort) then ." exception = " . (abort)
hdr x,'ERROR'
error: call docol
dw true ; -1
dw pof,error1
dw pabor
error1 dw lit,-2
dw pof,error3
dw boot,cellp,at
dw zequ
dw zbran,error2
dw doterr ; skipped by applications
error2 dw space
dw errmsg,tat
dw typee
dw pabor
error3 dw pdotq
dcs ' exception = '
dw dot
dw pabor
; ABORT ( -- ) -1 throw
hdr 1,'ABORT'
abort: mov ax,-1
push ax
; jmp throw
; THROW ( n -- ) ?dup if catcher @ ?dup 0= if error then rp!
; r> catcher ! 2r> fsp ! swap >r sp! drop r>
; then
hdr 1,'THROW'
throw: call docol
dw qdup
dw zbran,throw2
dw catchr,at
if debug
dw pdotq
dcs ' THROW:'
dw over,dot
dw pdotq
dcs 'CATCHER:'
dw dupp,udot
endif
dw qdup,zequ
dw zbran,throw1
dw error
throw1 dw rpsto
dw fromr,catchr,store
dw tfrom,fsp,store
dw swap,tor
dw spsto
dw drop
dw fromr
throw2 dw exit
; CATCH ( xt -- n | 0 ) sp@ fsp @ 2>r catcher @ >r rp@ catcher
; ! execute 0 r> catcher ! 2r> 2drop
hdr 1,'CATCH'
catch: call docol
dw spat
dw fsp,at
dw ttor
dw catchr,at,tor
dw rpat,catchr,store
dw exec
dw zero
dw fromr,catchr,store
dw tfrom
catch1 dw tdrop
dw exit
; (abort") ( n -- ) r> count 2dup + >r ?abort
hdr x,'(ABORT")'
pabq: sub ax,ax
lodsb
push si
push ax
add si,ax
; jmp qabor
; ?abort ( n c-addr u -- ) rot if errmsg 2! -2 throw then 2drop
hdr x,'?ABORT'
qabor: call docol
dw rot
dw zbran,catch1
dw errmsg,tstor ; only change msg on error
dw lit,-2
dw throw
; ABORT" state? if postpone (abort") ," end
; postpone s" ?abort ;immediate
hdr 1,'ABORT"',1,1
aborq: call docol
dw stateq
dw zbran,aborq1
dw comp,pabq
dw comq
dw exit
aborq1 dw squot
dw qabor
dw exit
; CMDTAIL ( -- c-addr u ) (dosbuf) count -blanks
hdr 1,'CMDTAIL'
cmdtail:call docol
dw clit
db dosbuf
dw count
dw dblan
dw exit
; Cold start from DOS
cseg
nodos db 'wrong DOS version',cr,lf,'$'
noram db 'not enough RAM',cr,lf,'$'
cldd: cld
mov ax,cs
mov ds,ax
mov cseg1,ax
mov hseg1,ax ; adjusted later
mov sp,offset tmpstk
mov ax,3000h ; check dos version
int 21h
mov byte ptr dosv,al
mov byte ptr dosv+cw,ah
cmp al,2
mov dx,offset nodos
mov ah,0
jc cldd2
mov ax,boot1 ; get BOOT word
mov iboot,ax ; save it
test ax,boot2
pushf
mov bx,ulimit ; turnkey limit
jnz cldd1
mov bx,em/16 ; default limit
add hseg1,bx ; set heads segment
add bx,hm/16 ; add heads space
cldd1: push cs
pop es
mov ah,4ah ; adjust memory
int 21h
mov dx,offset noram
mov ax,4C01h ; error-code = 1
jnc cldd3
cldd2: push ax
mov ah,9 ; show failure
int 21h
pop ax
int 21h ; terminate
cldd3: call gmode
and al,7fh ; ignore no-blank bit
mov word ptr imode,ax ; save video mode
mov bh,ah
mov ah,8
int 10h
mov iattr,ah ; save video attribute
mov ah,19h ; save current drive
int 21h
mov defdrv,al
mov ax,40h ; set keyboard type
mov es,ax
mov bx,96h
test byte ptr es:[bx],10h
mov ax,0100h ; old
jz cldd4
mov ax,1110h ; extended
cldd4: mov word ptr kbfn,ax
popf
jz cldd5 ; need forth system
mov word ptr prese,offset noop ; patch out forth init
mov di,ulimit+cw ; LIMIT for applications
jmp short cldd8
cldd5: mov byte ptr cmdf,0ffh ; enable command line flag
push ds ; move heads into place
mov di,idph
cldd6: sub cx,cx ; later patched to MOV CX,DI
dec di
mov si,di
mov es,hseg1
mov ax,ds
add ax,hstart
mov ds,ax
std
rep movsb
cld
pop ds
mov ax,idp ; move system into place
mov di,offset orig+sm
mov cx,idps
cldd7: sub cx,cx ; later patched to SUB CX,DI
call bmovu
inc di
cldd8: mov limit1,di ; patch LIMIT
db 0E9h ; 'jmp'
cldd9 dw movpat-$-2 ; later patched to 'cold'
; COLD ( -- )
hdr 1,'COLD' ; FIG
cold: cld
mov ax,cs
mov ds,ax
cli
mov ss,ax
mov sp,offset tmpstk
sti
mov word ptr esm,offset orig+fdbs ; patch end of system memory
mov ax,limit1 ; get LIMIT
sub ax,nus
mov bp,ax ; init return stack
mov ir0,ax ; patch R0
mov upp,ax ; patch UP
sub ax,nrts
mov fspp,ax ; init fp stack
mov ifs0,ax ; patch FS0
sub ax,nfps ; fp stack size
mov sp,ax ; init data stack
mov is0,ax ; patch S0
mov di,bp ; init boot up variables
mov ax,offset initu
mov cx,initu2-initu
call movd
mov word ptr pause1,0 ; patch PAUSE
mov ax,0500h ; set video page = 0
cold1: call video
call gmode ; get video mode
cmp al,7 ; 80 col mono
jz cold2
cmp al,3 ; 80 col color
jz cold2
cmp al,2 ; 80 col b/w
jz cold2
mov ax,3 ; set video mode = 80 col color
jmp cold1 ; (screen will blank)
cold2: dec bh ; cols
mov wmax,bh
sub bh,bh
sub dl,dl ; assume old CGA card
mov ax,1130h
call video
or dl,dl ; rows if EGA+
jnz cold3
mov dl,24
cold3: mov wmax+1,dl
mov word ptr wmin,0
mov al,iattr ; set default attribute
and al,7fh
mov cattr,al
mov dx,offset orig+dosbuf ; reset DOS DTA
mov ah,1ah
int 21h
call docol
dw smss ; calibrate MS
dw app ; default is APPLICATION
dw decim ; default base
dw reset ; general reset
prese equ $
dw freset ; forth reset
pinit equ $
dw init ; run INIT eg. for float
dw bootq
dw dupp,boot,store ; restore BOOT
dw qdup
dw zbran,cold6
dw exec ; run application
dw zero,retrn ; exit to DOS
aseg ; run forth interpreter
cold6 dw cmdtail ; process command-line
dw lit,cmdf
dw cat,andd
dw tuck
dw lit,tib ; copy to tib
dw zero,pstr
dw tsourc,tstor
dw zero
dw lit,cmdf ; disable
dw cstor
dw zbran,cold8
dw blword ; parse first word
dw at
dw lit
db 1,'-' ; skips file open
dw subb
dw zbran,cold7
dw inn,off
dw getfn,popen
cold7 dw inte ; interpret
cold8 dw vnorm
dw crr,pagee
dw pdotq
db elogo-$-1
logo equ $
db 'DX-Forth '
db '0'+rel,'.','0'+rev/10
db '0'+rev mod 10
db ' '
if beta
db 'unofficial test release'
else
date
endif
db ' '
elogo equ $
dw crr
piden equ $
dw ident ; run IDENTIFY
dw crr
dw scrnq
dw zbran,cold9
dw crr
dw pdotq
dcs 'Using '
dw loadf,typee
dw crr
cold9 dw pqui ; jump to interpreter
; SET-LIMIT ( addr -- ) $fff0 and dup 4 rshift (ulimit) 2!
hdr 1,'SET-LIMIT',,1
setlim: pop ax
and al,0f0h
mov ulimit+cw,ax
mov cl,4
shr ax,cl
mov ulimit,ax
nextt
; PROTECT ( -- ) up @ (initu) (initu2-initu) cmove
hdr 1,'PROTECT',,1
prot: call docol
dw up,at
dw lit,initu
dw lit,initu2-initu
dw cmove
dw exit
; 'prune variable 'prune 'prune off
hdr x,"'PRUNE",,1
tprun: call docre
dw toppru ; 0=end
; REMEMBER ( xt -- ) 'prune link, ,
hdr 1,'REMEMBER',,1 ; add xt to prunes
remem: call docol
dw tprun,linkc
dw comma
dw exit
; xdp ( adr -- adr xdp ) dup limit u< if dp else dps then
hdr x,'XDP',,1
xdp: pop ax
push ax
cmp ax,limit1
jnc xdp1
jmp dpp
xdp1: jmp dps
; prunes ( -- ) begin 'prune @ dup while dup xdp @ u< 0=
; while 2@ 'prune ! execute repeat then drop
hdr x,'PRUNES',,1
pruns: call docol
pruns1 dw tprun,at
dw dupp
dw zbran,pruns2
dw dupp
dw xdp,at
dw uless,zequ
dw zbran,pruns2
dw tat
dw tprun,store
dw exec
dw bran,pruns1
pruns2 dw drop
dw exit
; ?protected ( h-addr -- h-addr ) (idph) @ over u> check? and
; abort" is protected"
hdr x,'?PROTECTED',,1
qprot: call docol
dw lit,idph
dw at
dw over,ugrea
dw chkq,andd
dw pabq
dcs 'is protected'
dw exit
; name? ( "name" -- xt nfa ) bl-word get-context wfind ?defined
; ?protected
hdr x,'NAME?',,1 ; find name in context wordlist
nameq: call docol
dw blword
dw getcon
dw wfind,qdef
dw qprot
dw exit
; lfind ( wid nfa -- lfa | 0 ) swap @ begin 2dup h@ - while h@
; dup while n>link repeat then nip
hdr x,'LFIND',,1 ; find link field containing nfa, 0=none
lfind: call docol
dw swap,at
lfind1 dw tdup,hat
dw subb
dw zbran,lfind2
dw hat,dupp
dw zbran,lfind2
dw nlnk
dw bran,lfind1
lfind2 dw nip
dw exit
; BEHEAD ( "name1" "name2" -- ) name? nip name? nip 2dup u< if swap
; then n>name get-context rot lfind h!
hdr 1,'BEHEAD',,1 ; unlink word heads
behead: call docol
dw nameq,nip
dw nameq,nip
dw tdup,uless
dw zbran,behead1
dw swap
behead1 dw ntnam
dw getcon
dw rot,lfind
dw hstor
dw exit
; ?chain ( flag -- ) abort" invalid chain"
hdr x,'?CHAIN',,1
qchai: call docol
dw pabq
dcs 'invalid chain'
dw exit
; CHAIN ( "name" -- ) get-current postpone addr @ 2dup
; = ?chain @ cell- $2001 over h@ -
; ?chain 2dup lfind ?chain swap 0
; lfind ?protected 2dup u> ?chain h!
hdr 1,'CHAIN',,1
chain: call docol
dw getcur
dw addr,at
dw tdup,equal ; same wordlist
dw qchai
dw at,cellm
dw lit,2001h
dw over,hat,subb ; not a wordlist
dw qchai
dw tdup,lfind ; already chained
dw qchai
dw swap
dw zero,lfind
dw qprot
dw tdup,ugrea ; forward reference
dw qchai
dw hstor
dw exit
; (forget) ( nfa dps dp -- )
; dp 2! >r voc-link begin @ dup cell- @ cell+
; r@ u< until dup voc-link ! begin dup cell-
; @ dup h@ begin dup r@ u< 0= while -alias if
; dup name> xdp tuck @ umin swap ! then n>name
; repeat swap h! @ ?dup 0= until r> dup dph !
; (idph) @ u< if protect then prunes
hdr x,'(FORGET)',,1
pforg: call docol
dw dpp,tstor ; starting maximums
dw tor
dw vocl ; trim vocs > nfa
pforg1 dw at
dw dupp
dw cellm,at,cellp ; vocab nfa (WORDLIST compatible)
dw rat,uless
dw zbran,pforg1
dw dupp,vocl,store
pforg2 dw dupp,cellm,at ; scan remaining vocs
dw dupp,hat
pforg3 dw dupp,rat ; for each word >= nfa
dw uless,zequ
dw zbran,pforg5
dw dalias ; not an alias
dw zbran,pforg4
dw dupp,namef ; get its xt
dw xdp
dw tuck,at
dw umin,swap,store ; trim dict
pforg4 dw ntnam
dw bran,pforg3
pforg5 dw swap,hstor
dw at
dw qdup,zequ
dw zbran,pforg2 ; until all vocs done
dw fromr
dw dupp,dph,store
dw lit,idph ; below fence?
dw at,uless
dw zbran,pforg6
dw prot ; fix bootup values
pforg6 dw pruns ; run prunes list
dw exit
; EMPTY ( -- ) forth definitions (idph) @ (idp)
; 2@ (forget)
hdr 1,'EMPTY',,1
empty: call docol
dw forth,defin ; switch to a safe vocabulary
dw lit,idph
dw at
dw lit,idp
dw tat
dw pforg
dw exit
; FORGET ( "name" -- ) get-current context ! name? -alias
; 0= abort" is alias" swap limit over u<
; if dp @ else dps @ swap then (forget)
hdr 1,'FORGET',,1
forg: call docol
dw getcur
dw cont,store
dw nameq
dw dalias,zequ ; alias?
dw pabq
dcs 'is alias'
dw swap
dw limit
dw over,uless
dw zbran,forg1
dw dpp,at
dw bran,forg2
forg1 dw dps,at
dw swap
forg2 dw pforg
dw exit
; MARKER ( "name" -- ) sys? system ['] drop build sys !
hdr 1,'MARKER',,1
marker: call docol
dw sysq
dw system
dw lit,drop
dw build
dw sys,store
dw exit
; COMPILE, ( xt -- ) warning @ 0< if dup limit u< sys? d0=
; if dup .name ." is system " then then ,
hdr 1,'COMPILE,',,1
comxt: call docol
dw warnn,at
if wopt
dw zless
endif
dw zbran,comxt1
dw dupp,limit
dw uless
dw sysq
dw dzequ
dw zbran,comxt1
dw dupp
dw dotnam
dw pdotq
dcs ' is system '
comxt1 dw comma
dw exit
; COMPILE ( -- ) ?comp r> dup cell+ >r @ compile,
hdr 1,'COMPILE',,1
comp: call docol
dw qcomp ; prevent crash if interpreting
dw fromr
dw dupp,cellp
dw tor
dw at
dw comxt
dw exit
; POSTPONE defined dup ?defined 0< if compile
; compile then compile, ;immediate
hdr 1,'POSTPONE',1,1
postp: call docol
dw defined
dw dupp,qdef
dw zless
dw zbran,postp1
dw comp,comp
postp1 dw comxt
dw exit
; S, ( c-addr u -- ) 255 umin here over 1+ allot place
hdr 1,'S,',,1
scomm: call docol
dw clit
db 255
dw umin
dw here,over
dw onep,allot
dw place
dw exit
; ," ( "ccc" -- ) [char] " /parse s,
hdr 1,',"',,1
comq: call docol
dw clit
db '"'
dw spars
dw scomm
dw exit
; (s") ( -- c-addr u ) r> count 2dup + >r
hdr x,'(S")'
psqot: sub ax,ax
lodsb
push si
push ax
add si,ax
nextt
; SLITERAL ( c-addr u -- ) postpone (s") s, ;immediate
hdr 1,'SLITERAL',1,1
slite: call docol
dw comp,psqot
dw scomm
dw exit
; S" ( -- c-addr u ) [char] " /parse state? if postpone sliteral
; then ;immediate
hdr 1,'S"',1,1 ; state smart version
squot: call docol
dw clit
db '"'
dw spars
dw stateq
dw zbran,squot1
dw slite
squot1 dw exit
if 0
; (c") ( -- c-addr ) r> dup count + >r
hdr x,'(C")'
pcqot: push si
sub ax,ax
lodsb
add si,ax
nextt
; C" ( -- c-addr ) postpone (c") ," ;immediate
hdr 1,'C"',1,1
cquot: call docol
dw comp,pcqot
dw comq
dw exit
endif
; (.") r> count 2dup + >r type
hdr x,'(.")'
pdotq: sub ax,ax
lodsb
push si
push ax
add si,ax
jmp typee
; ." postpone (.") ," ;immediate
hdr 1,'."',1,1
dotq: call docol
dw comp,pdotq
dw comq
dw exit
; CHAR? ( x -- x flag )
hdr x,'CHAR?',,1
charq: pop ax
push ax
mov al,ah
jmp zequ1
; LITERAL ( n -- ) char? if postpone clit c, end
; postpone lit , ;immediate
hdr 1,'LITERAL',1,1
liter: call docol
dw charq
dw zbran,liter1
dw comp,clit
dw ccomm
dw exit
liter1 dw comp,lit
dw comma
dw exit
; 2LITERAL ( x1 x2 -- ) postpone 2lit , , ;immediate
hdr 1,'2LITERAL',1,1
tlite: call docol
dw comp,tlit
dw comma,comma
dw exit
; ['] ' postpone literal ;immediate
hdr 1,'['']',1,1
btick: call docol
dw tick
dw liter
dw exit
; [COMPILE] ' compile, ;immediate
hdr 1,'[COMPILE]',1,1
bcomp: call docol
dw tick
dw comxt
dw exit
; RECURSE ( -- ) last cell+ @ compile, ;immediate
hdr 1,'RECURSE',1,1
recurs: push last2
jmp comxt
; CHAR ( -- char ) bl-word 1+ c@
hdr 1,'CHAR',,1
char: call docol
dw blword
dw onep,cat
dw exit
; [CHAR] ( -- char ) char postpone literal ;immediate
hdr 1,'[CHAR]',1,1
pchar: call docol
dw char
dw liter
dw exit
; Y/N ( -- flag ) ." (y/n) N\bs" key upcase [char] Y = dup
; if [char] Y else [char] N then emit space
hdr 1,'Y/N'
yn: call docol
dw pdotq
dcs '(y/n) N',bs
dw key,upcas
dw clit
db 'Y'
dw equal,dupp
dw zbran,yn1
dw clit
db 'Y'
dw bran,yn2
yn1 dw clit
db 'N'
yn2 dw emit,space
dw exit
;
; File and Block Functions
;
; PATH -PATH filetype? +EXT -EXT FILE-POSITION FILE-SIZE
; RESIZE-FILE REPOSITION-FILE READ-FILE LREAD WRITE-FILE
; LWRITE fh READ-LINE WRITE-LINE >FNAME R/O W/O R/W BIN
; OPEN-FILE CREATE-FILE CLOSE-FILE FLUSH-FILE FILE-STATUS
; DELETE-FILE RENAME-FILE sfp SWAP-FILE FDB fnb scr#
; blks fid fd buf blk# SCREEN? LOADFILE ?open #SCREENS
; EMPTY-BUFFERS UPDATE blkerr blk-rw ?blk SAVE-BUFFERS
; FLUSH BUFFER BLOCK --> LOAD THRU FILEBLOCKS CLOSE
; CLOSE-ALL LASTFILE .lastfile ?create init-scr OPEN
; (open) GETFILENAME USING LOADED FLOAD SAVE TURNKEY
; TURNKEY-SYSTEM
; PATH ( u1 -- c-addr u2 ior )
hdr 1,'PATH' ; uses filename buffer
path: pop ax
or ax,ax
jnz path1
mov ah,19h
int 21h
inc al
path1: mov dl,al
mov bx,zbuf1
push bx
add al,'@'
mov [bx],al
inc bx
mov [bx],'\:'
add bx,2
push si
mov si,bx
mov ah,47h
int 21h
pop si
jc path3
pop bx
push bx
push ds
pop es
call zcnt2
cmp ax,3
jz path2
mov byte ptr [bx],'\'
inc ax
path2: push ax
jmp zero
path3: mov dx,0 ; don't change CF
push dx
jmp doserr1
; -PATH ( c-addr1 u1 -- c-addr2 u2 )
; 2dup [char] : scan dup if 1 /string 2swap
; then begin 2drop 2dup [char] \ scan dup
; while 1 /string 2swap repeat 2drop
hdr 1,'-PATH'
dpath: call docol
dw tdup
dw clit
db ':'
dw scan
dw dupp
dw zbran,dpath1
dw one,sstr
dw tswap
dpath1 dw tdrop
dw tdup
dw clit
db '\'
dw scan,dupp
dw zbran,dpath2
dw one,sstr
dw tswap
dw bran,dpath1
dpath2 dw tdrop
dw exit
; filetype? ( c-addr1 u1 -- u2 ) -path [char] . scan nip
hdr x,'FILETYPE?' ; get filetype length
ftype: call docol
dw dpath
dw clit
db '.'
dw scan
dw nip
dw exit
; +EXT ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 )
; 2over filetype? if 2drop end 3 min
; s" ." 2rot -trailing (pfsiz-5) min zbuf
; @ 1+ 0 +string +string +string
hdr 1,'+EXT' ; uses filename buffer
pext: call docol
dw tover,ftype
dw zbran,pext1
dw tdrop,exit
pext1 dw three,min
dw psqot
dcs '.'
dw trot
dw dtrai ; trim trailing blanks
dw clit
db pfsiz-5
dw min
dw zbuf,at ; unused
dw onep
dw zero
dw pstr
dw pstr
dw pstr
dw exit
; -EXT ( c-addr1 u1 -- c-addr2 u2 ) 2dup filetype? -
hdr 1,'-EXT'
dext: call docol
dw tdup,ftype
dw subb
dw exit
; FILE-POSITION ( fileid -- ud ior )
hdr 1,'FILE-POSITION'
fpos: pop bx
sub cx,cx
mov dx,cx
mov ax,4201h
int 21h
push ax
push dx
fpos1: jmp doserr1
; FILE-SIZE ( fileid -- ud ior )
hdr 1,'FILE-SIZE'
fsiz: pop bx
sub cx,cx
mov dx,cx
mov ax,4201h
int 21h
push ax
push dx
jc fpos1
mov dx,cx ; assume CX BX unchanged
mov ax,4202h
int 21h
pop cx
pop di
push ax
push dx
mov dx,di
mov ax,4200h
int 21h
jmp zero
; RESIZE-FILE ( ud fileid -- ior )
hdr 1,'RESIZE-FILE'
resizf: pop bx
pop cx
pop dx
mov ax,4200h
int 21h
jc resizf2
sub cx,cx ; truncate file
mov ah,40h ; assume BX unchanged
resizf1:int 21h
resizf2:jmp doserr1
; REPOSITION-FILE ( ud fileid -- ior )
hdr 1,'REPOSITION-FILE'
reposf: pop bx
pop cx
pop dx
mov ax,4200h
jmp resizf1
; READ-FILE ( c-addr u1 fileid -- u2 ior )
hdr 1,'READ-FILE'
readf: pop bx
pop cx
pop dx
push ds
readf1: pop ax
mov ds,ax
mov ah,3fh
readf2: int 21h
push cs
pop ds
push ax
jmp doserr1
; LREAD ( seg offs u fileid -- ior )
hdr 1,'LREAD'
lread: pop bx
pop cx
pop dx
jmp readf1
; WRITE-FILE ( c-addr u fileid -- ior )
hdr 1,'WRITE-FILE'
writf: pop bx
pop cx
pop dx
push ds
writf1: pop ax
or cx,cx ; must trap CX=0
jnz writf2
jmp zero
writf2: mov ds,ax
mov ah,40h
int 21h
push cs
pop ds
jc writf3
cmp ax,cx ; assume CX unchanged
mov al,255
writf3: jmp doserr1
; LWRITE ( seg offs u fileid -- ior )
hdr 1,'LWRITE'
lwrit: pop bx
pop cx
pop dx
jmp writf1
; fh ( -- fid ) 0 value fh
hdr x,'FH'
fh: call doval
dw ?
; READ-LINE ( addr u1 fid -- u2 flag ior )
; to fh over swap fh read-file ?dup if end
; 2dup bounds ?do i dup c@ $1A = if rot -
; fh file-size drop fh reposition-file drop
; leave then c@ eol rot scan nip ?dup if i
; + >r over + r> swap - dup 0<> fh
; file-position drop d+ fh reposition-file
; drop i swap - -1 0 unloop end loop nip
; dup 0<> 0
hdr 1,'READ-LINE'
readl: call docol
dw pto,fh
dw over,swap
dw fh,readf,qdup
dw zbran,readl1
dw exit
readl1 dw tdup,bounds
dw xqdo,readl5
readl2 dw ido
dw dupp,cat
dw clit
db ctlz
dw equal
dw zbran,readl3
dw rot,subb
dw fh,fsiz,drop
dw fh,reposf,drop
dw pleav,readl2-cw
readl3 dw cat
dw eol,rot
dw scan,nip
dw qdup
dw zbran,readl4
dw ido,plus,tor
dw over,plus
dw fromr
dw swap,subb
dw dupp,zneq ; handle buffer > 32K
dw fh,fpos,drop
dw dplus
dw fh,reposf,drop
dw ido,swap,subb
dw true,zero
dw unloo,exit
readl4 dw xloop,readl2
readl5 dw nip
dw dupp,zneq,zero
dw exit
; WRITE-LINE ( c-addr u fileid -- ior )
; dup >r write-file ?dup if r> drop end
; eol r> write-file
hdr 1,'WRITE-LINE'
writl: call docol
dw dupp,tor
dw writf
dw qdup
dw zbran,writl1
dw fromr,drop
dw exit
writl1 dw eol
dw fromr
dw writf
dw exit
; >FNAME ( addr1 u -- addr2 ) -blanks (pfsiz-1) min zbuf @ pack
; 0 affix zbuf 2@ swap zbuf 2!
hdr 1,'>FNAME'
tfnam: call docol
dw dblan
dw clit
db pfsiz-1
dw min
dw zbuf,at
dw pack
dw zero,affix ; trailing null
dw zbuf,tat
dw swap
dw zbuf,tstor
dw exit
cseg
pascii: push bx
push ax
call docol
dw tfnam,onep
dw exit1
pop dx ; addr
ret
; R/O ( -- fam ) aka 0 r/o
hdr 1,'R/O',,,zero
rso equ zero
; W/O ( -- fam ) aka 1 w/o
hdr 1,'W/O',,,one
wso equ one
; R/W ( -- fam ) aka 2 r/w
hdr 1,'R/W',,,two
rsw equ two
; BIN ( fam1 -- fam2 ) aka noop bin immediate
hdr 1,'BIN',1,,noop
binn equ next
; OPEN-FILE ( c-addr u fam -- fileid ior )
hdr 1,'OPEN-FILE'
openf: pop dx
pop ax
pop bx
push dx
call pascii
openf1: pop ax ; fam
mov ah,3dh
jmp readf2
; CREATE-FILE ( c-addr u fam -- fileid ior )
hdr 1,'CREATE-FILE'
creatf: pop dx
pop ax
pop bx
push dx ; fam (or dummy fileid if fail)
call pascii
push dx ; asciiz
sub cx,cx ; normal attribute
mov ah,3ch
int 21h
jnc creatf1
pop dx ; discard
jmp doserr1 ; failed
creatf1:mov bx,ax ; close and re-open file using fam
mov ah,3eh
int 21h
pop dx ; asciiz
jmp openf1
; CLOSE-FILE ( fileid -- ior )
hdr 1,'CLOSE-FILE'
closf: pop bx
mov ah,3eh
jmp resizf1
; FLUSH-FILE ( fileid -- ior )
hdr 1,'FLUSH-FILE'
flusf: pop bx
mov ah,45h
int 21h
jc flusf1
push ax
jmp closf
flusf1: jmp doserr1
; FILE-STATUS ( c-addr u -- x ior ) get file attributes
hdr 1,'FILE-STATUS'
statf: pop ax
pop bx
call pascii
mov ax,4300h
int 21h
push cx
jmp doserr1
; DELETE-FILE ( c-addr u -- ior )
hdr 1,'DELETE-FILE'
delf: pop ax
pop bx
call pascii
mov ah,41h
jmp resizf1
; RENAME-FILE ( c-addr1 u1 c-addr2 u2 -- ior )
hdr 1,'RENAME-FILE'
renf: pop ax
pop bx
call pascii
pop ax
pop bx
push dx
call pascii
pop di
mov ax,ds
mov es,ax
mov ah,56h
int 21h
jmp doserr1
; screen file selector
aseg
fdtab: gfdb ; fdb table
; sfp ( -- a )
hdr x,'SFP',,1
sfp: call docre
sfp1 dw fdtab ; current
sfp2 dw fdtab+cw ; swap-file
; SWAP-FILE ( -- ) screen? if scr @ scr# ! then sfp 2@ swap
; sfp 2! scr# @ scr ! empty-buffers
hdr 1,'SWAP-FILE',,1
swapf: call docol
dw scrnq
dw zbran,swapf1
dw scr,at
dw snum,store
swapf1 dw sfp,tat
dw swap
dw sfp,tstor
dw snum,at
dw scr,store
dw mtbuf
dw exit
; FDB ( -- addr ) (fdtab) (nfd) 0 do dup @ @ 0= if unloop end
; cell+ loop abort" too many files"
hdr 1,'FDB',,1 ; get a free slot
fdb: mov bx,offset fdtab
mov cx,nfd
fdb1:
; cmp bx,sfp2 ; skip swap-file
; jz fdb2
mov di,[bx]
cmp word ptr [di],0
jz fdb3
fdb2: inc bx
inc bx
loop fdb1
call docol
dw one
dw pabq
dcs 'too many files'
fdb3: push bx
nextt
; file descriptor fields
;
; FD cell status 0=closed
; FID cell file handle
; BLKS cell file size (blocks)
; SCR# cell current SCR#
; FNB 'pfsiz' bytes file name
; fnb ( -- addr )
hdr x,'FNB',,1
fnb: mov al,cw*4 ; file name field
ignore2
; scr# ( -- addr )
hdr x,'SCR#',,1
snum: mov al,cw*3 ; current SCR# field
ignore2
; blks ( -- addr )
hdr x,'BLKS',,1
blks: mov al,cw*2 ; file size field
ignore2
; fid ( -- addr )
hdr x,'FID',,1
fid: mov al,cw*1 ; file handle field
ignore2
; fd ( -- addr )
hdr x,'FD',,1
fd: mov al,0 ; file descriptor field
sub ah,ah
mov di,sfp1
add ax,[di]
jmp apush
; buf ( -- addr )
hdr x,'BUF',,1
buf: call docon ; file buffer address
dw sfb
; blk# ( -- addr )
hdr x,'BLK#',,1
bnum: call docre ; block#, update flag
bnum1 dw ?
; SCREEN? ( -- flag ) fd @ 0<
hdr 1,'SCREEN?',,1
scrnq: call docol
dw fd,at
dw zless
dw exit
; LOADFILE ( -- c-addr u ) fnb count
hdr 1,'LOADFILE',,1
loadf: call docol
dw fnb,count
dw exit
; ?open ( -- ) screen? 0= abort" no file open"
hdr x,'?OPEN',,1
qopen: call docol
dw scrnq
dw zequ
dw pabq
dcs 'no file open'
dw exit
; #SCREENS ( -- +n ) ?open blks @
hdr 1,'#SCREENS',,1
nscr: call docol
dw qopen
dw blks,at
dw exit
; EMPTY-BUFFERS ( -- ) $7fff blk# !
hdr 1,'EMPTY-BUFFERS',,1
mtbuf: mov bnum1,7fffh
nextt
; UPDATE ( -- ) ?open blk# @ $8000 or blk# !
hdr 1,'UPDATE',,1
update: call docol
dw qopen
dw exit1
or bnum1,8000h
nextt
; blkerr ( flag -- ) abort" block r/w error"
hdr x,'BLKERR',,1
blkerr: call docol
dw pabq
dcs 'block r/w error'
dw exit
; blk-rw ( +n mode -- ) >r b/buf um* fid @ reposition-file blkerr
; buf b/buf fid @ r> if write-file blkerr
; fid @ flush-file else read-file blkerr
; b/buf < then blkerr
hdr x,'BLK-RW',,1
blkrw: call docol
dw tor
dw bbuf,umstr
dw fid,at
dw reposf
dw blkerr
dw buf,bbuf
dw fid,at
dw fromr
dw zbran,blkrw1
dw writf
dw blkerr
dw fid,at
dw flusf ; flush CP/M 3 buffers
dw bran,blkrw2
blkrw1 dw readf
dw blkerr
dw bbuf,less
blkrw2 dw blkerr
dw exit
; ?blk ( +n -- +n ) dup #screens 0 within
; abort" block out of range"
hdr x,'?BLK',,1
qblk: call docol
dw dupp
dw nscr,zero
dw within ; block in range?
dw pabq
dcs 'block out of range'
dw exit
; SAVE-BUFFERS ( -- ) ?open blk# @ 0< if blk# @ $7fff and
; dup blk# ! ?blk 1 blk-rw then
hdr 1,'SAVE-BUFFERS',,1
savbuf: call docol
dw qopen
dw bnum,at
dw zless
dw zbran,savbuf1
dw bnum,at
dw lit,7fffh
dw andd
dw dupp
dw bnum,store
dw qblk ; block in range?
dw one,blkrw
savbuf1 dw exit
; FLUSH ( -- ) save-buffers empty-buffers
hdr 1,'FLUSH',,1
flush: call docol
dw savbuf,mtbuf
dw exit
; BUFFER ( +n -- addr ) save-buffers ?blk blk# ! buf
hdr 1,'BUFFER',,1
buffer: call docol
dw savbuf
dw qblk
dw bnum,store
dw buf
dw exit
; BLOCK ( +n -- addr ) ?open blk# @ $7fff and over - if dup
; buffer drop 0 blk-rw else drop then buf
hdr 1,'BLOCK',,1
block: call docol
dw qopen
dw bnum,at
dw lit,7fffh
dw andd,over,subb
dw zbran,block1
dw dupp,buffer,drop
dw zero,blkrw
dw bran,block2
block1 dw drop
block2 dw buf
dw exit
; --> ( -- ) blk @ 0= abort" loading only" (refill) drop
; ;immediate
hdr 1,'-->',1,1
arrow: call docol
dw blk,at
dw zequ
dw pabq
dcs 'loading only'
dw prefil,drop
dw exit
; (thru) ( +n1 +n2 -- ) 1+ swap ?do i block b/buf i (eval) loop
hdr x,'(THRU)',,1
pthru: call docol
dw onep,swap
dw xqdo,pthru2
pthru1 dw ido,block
dw bbuf
dw ido,peval
dw xloop,pthru1
pthru2 dw exit
; LOAD ( +n -- ) dup thru
hdr 1,'LOAD',,1
load: pop ax
push ax
push ax
; jmp thru
; THRU ( +n1 +n2 -- ) (thru) ?block
hdr 1,'THRU',,1
thru: call docol
dw pthru
dw qblock
dw exit
; (fbk) ( +n -- ) #screens 2dup u< if drop dup then dup b/buf
; um* fid @ resize-file throw over blks ! ?do
; i buffer b/buf blank update save-buffers loop
hdr x,'(FBK)',,1
pfbk: call docol
dw nscr ; tests if file open
dw tdup,uless
dw zbran,pfbk1
dw drop,dupp
pfbk1 dw dupp
dw bbuf,umstr
dw fid,at
dw resizf,throw
pfbk2 dw over
dw blks,store ; update max block
dw xqdo,pfbk4
pfbk3 dw ido,buffer
dw bbuf,blank
dw update,savbuf
dw xloop,pfbk3
pfbk4 dw exit
; FILEBLOCKS ( +n -- ) ['] (fbk) catch abort" can't resize file"
hdr 1,'FILEBLOCKS',,1
fbloc: call docol
dw lit,pfbk
dw catch
dw pabq
dcs 'can''t resize file'
dw exit
; CLOSE ( -- ) screen? if flush fid @ close-file drop
; fd off then empty-buffers
;
; NOTE: errors are NOT reported with this function
hdr 1,'CLOSE',,1 ; close current file
close: call docol
dw scrnq
dw zbran,close1
dw flush
dw fid,at
dw closf,drop
dw fd,off
close1 dw mtbuf
dw exit
; CLOSE-ALL ( -- ) close (fdtab) nfd 0 do dup sfp ! close
; cell+ loop drop
hdr 1,'CLOSE-ALL',,1
closa: call docol
dw close ; ensure buffer flushed
dw lit,fdtab
dw clit
db nfd
dw zero
dw xdo,closa2
closa1 dw dupp
dw sfp,store
dw close
dw cellp
dw xloop,closa1
closa2 dw drop
dw exit
; LASTFILE ( -- c-addr u ) zbuf cell+ @ count
hdr 1,'LASTFILE',,1
lastf: call docol ; last named file used by open-file etc
dw zbuf,cellp
dw at,count
dw exit
; .lastfile ( -- ) beep cr lastfile type space
hdr x,'.LASTFILE',,1
dotlf: call docol
dw beep,crr
dw lastf,typee
dw space
dw exit
; ?create ( c-addr u -- fileid )
; r/o open-file 0= tuck if close-file then
; drop if .lastfile ." exists - delete it? "
; y/n 0= if abort then then lastfile r/w
; create-file abort" can't create file"
hdr x,'?CREATE',,1
qcreat: call docol
dw rso,openf ; test if file exists
dw zequ,tuck
dw zbran,qcreat1
dw closf
qcreat1 dw drop
dw zbran,qcreat2
dw dotlf
dw pdotq
dcs 'exists - delete it? '
dw yn,zequ
dw zbran,qcreat2
dw abort
qcreat2 dw lastf,rsw,creatf
dw pabq
dcs 'can''t create file'
dw exit
; init-scr ( fileid ior -- ) if drop end fdb sfp ! fd on
; dup fid ! file-size drop b/buf
; um/mod nip blks ! lastfile fnb
; pack count upper empty-buffers
hdr x,'INIT-SCR',,1
iniscr: call docol ; init screenfile
dw zbran,iniscr1
dw drop
dw exit
iniscr1 dw fdb,sfp,store
dw fd,on
dw dupp,fid,store
dw fsiz,drop
dw bbuf,umslm,nip ; overflow stores $FFFF
dw blks,store
dw lastf,fnb,pack
dw count,upper
dw mtbuf
dw exit
; OPEN ( c-addr u fam -- ior ) fdb drop >r s" scr" +ext r>
; open-file tuck init-scr
hdr 1,'OPEN',,1 ; open a screen file
open: call docol
dw fdb,drop ; free slot?
dw tor
dw psqot
dcs 'scr'
dw pext
dw fromr,openf
dw tuck
dw iniscr
dw exit
; (open) ( c-addr u -- ) r/w open abort" can't open file"
hdr x,'(OPEN)',,1
popen: call docol
dw rsw,open
dw pabq
dcs 'can''t open file'
dw exit
; GETFILENAME ( -- c-addr u ) >in @ char dup rot >in ! [char] "
; - if drop bl then word count dup
; 0= abort" specify filename"
; GETFILENAME ( -- c-addr u ) token dup 0= abort" specify filename"
hdr 1,'GETFILENAME',,1
getfn: call docol
dw token
dw dupp,zequ
dw pabq
dcs 'specify filename'
dw exit
; USING ( "filename[.SCR]" -- ) close getfilename r/w open ?dup if
; .lastfile -507 = if ." access denied"
; 0 else ." not found - create it? "
; y/n then 0= if abort then lastfile
; ?create 0 init-scr then 0 0 scr 2!
hdr 1,'USING',,1 ; open/make a screen file
using: call docol
dw close
dw getfn
dw rsw,open,qdup
dw zbran,using4
dw dotlf
dw lit,-507
dw equal
dw zbran,using1
dw pdotq
dcs 'access denied'
dw zero
dw bran,using2
using1 dw pdotq
dcs 'not found - create it? '
dw yn
using2 dw zequ
dw zbran,using3
dw abort
using3 dw lastf,qcreat
dw zero,iniscr
using4 dw zero,zero ; reset SCR
dw scr,tstor
dw exit
; LOADED ( +n1 +n2 c-addr u -- ) sfp @ >r (open) (thru) close r>
; sfp ! ?block
hdr 1,'LOADED',,1
loaded: call docol
dw sfp,at
dw tor
dw popen
dw pthru
dw close
dw fromr
dw sfp,store
dw qblock
dw exit
; FLOAD ( +n "filename[.SCR]" -- ) dup getfilename loaded
hdr 1,'FLOAD',,1
fload: call docol
dw dupp
dw getfn
dw loaded
dw exit
cseg
hstart dw ? ; segment offset of heads in image
aseg
exehdr db 'MZ' ; 0 EXE id
dw ? ; 2 file size (mod 512)
dw ? ; 4 file size (512 byte blocks)
dw 0 ; 6 # relocation items
dw 2 ; 8 exe header size (paragraphs)
dw 0 ; A minimum paragraphs needed
dw 0FFFFh ; C maximum paragraphs needed
dw 0FFF0h ; E stack segment
dw tmpstk ;10 stack offset
dw 0 ;12 checksum (ignored by DOS)
dw start ;14 start address
dw 0FFF0h ;16 code segment
dw 1Ch ;18 offset 1st relocation
dw 0 ;1A overlay # 0=resident code
dw 0 ;1C null relocation item
dw 0 ;1E " "
; SAVE ( "filename[.EXE]" -- )
; 0 0 protect getfilename s" exe" +ext
; ?create >r over swap boot 2! (logo) (zb1)
; dup (zbsiz*2) erase (elogo-logo) cmove
; (exehdr) (100h-20h) $20 cmove 0= >r hseg
; 0 dph @ r@ and limit dp 2@ >r over - r@ +
; $0F + $FFF0 and r@ - r> over + 4 rshift
; (hstart) ! r> and (100h-20h) dp @ over -
; dup 3 pick + 0 6 pick m+ 512 um/mod over
; 0<> - swap (100h-20h+2) 2! r@ write-file
; boot cell+ off ?dup 0= if r@ write-file
; ?dup 0= if r@ lwrite then then r>
; close-file or abort" can't save file"
hdr 1,'SAVE',,1
save: call docol
dw zero,zero
save1 dw prot
dw getfn
dw psqot
dcs 'exe'
dw pext
dw qcreat
dw tor ; fid
dw over,swap ; set boot flags
dw boot,tstor
dw lit,logo ; insert compiler logo
dw lit,zb1
dw dupp
dw clit
db zbsiz*2
dw erase
dw clit
db elogo-logo
dw cmove
dw lit,exehdr ; position header
dw lit,100h-20h
dw clit
db 20h
dw cmove
dw zequ,tor ; system flag
dw hseg,zero
dw dph,at
dw rat,andd ; heads size
dw limit
dw dpp,tat
dw tor
dw over,subb
dw rat,plus
dw clit
db 0fh
dw plus
dw lit,0fff0h
dw andd
dw rat,subb
dw fromr
dw over,plus
dw clit
db 4
dw rsh
dw lit,hstart
dw store
dw fromr,andd ; system size
dw clit
db 100h-20h
dw dpp,at
dw over,subb
dw dupp
dw three,pick
dw plus
dw zero
dw clit
db 6
dw pick
dw mplus
dw lit,512
dw umslm
dw over,zneq,subb
dw swap
dw lit,100h-20h+2
dw tstor
dw rat,writf ; save application
dw boot,cellp,off ; reset forth flag
dw qdup,zequ
dw zbran,save2 ; error
dw rat,writf ; save system
dw qdup,zequ
dw zbran,save2 ; error
dw rat,lwrit ; save heads
save2 dw fromr,closf
dw orr
dw pabq
dcs 'can''t save file'
dw exit
; TURNKEY ( "bootword" "filename[.EXE]" -- )
hdr 1,'TURNKEY',,1
turnk: call docol
dw true
turnk1 dw tick
dw bran,save1
; TURNKEY-SYSTEM ( "bootword" "filename[.EXE]" -- )
hdr 1,'TURNKEY-SYSTEM',,1
turnks: call docol
dw zero
dw bran,turnk1
; CHAR+ ( c-addr1 -- c-addr2 ) aka 1+ char+
hdr 1,'CHAR+',,,onep
charp equ onep
; CHARS ( n1 -- n2 ) aka noop chars immediate
hdr 1,'CHARS',1,,noop
chars equ next
; CELL+ ( addr1 -- addr2 ) aka 2+ cell+
hdr 1,'CELL+',,,twop
cellp equ twop
; CELL- ( addr1 -- addr2 ) aka 2- cell-
hdr 1,'CELL-',,,twom
cellm equ twom
; CELLS ( n1 -- n2 ) aka 2* cells
hdr 1,'CELLS',,,tstar
cells equ tstar
; ALIGN ( -- ) aka noop align immediate
hdr 1,'ALIGN',1,,noop
alignn equ next
; ALIGNED ( addr -- a-addr ) aka noop aligned immediate
hdr 1,'ALIGNED',1,,noop
alignd equ next
if float
;
; Floating Point Functions
;
; -FP FLOAT+ FLOATS FALIGN FALIGNED F, FLITERAL FCONSTANT
; FVARIABLE FDEPTH FDROP FDUP FSWAP FOVER FROT F@ F! FPICK
; FABS FNEGATE D>F F>D S>F F>S F0= F= F0< F< F0> F>
; FMIN FMAX FLOOR FROUND FTRUNC FCEIL F+ F- F* F/ FRANDOM
; MAX-PRECISION REPRESENT >FLOAT PRECISION SET-PRECISION (FS.)
; FS.R FS. (FE.) FE.R FE. (F.) F.R F. (G.) G.R G. FSQRT
; FEXP FLN F** FSIN FCOS FATAN PI fpinit fident fnumber
;
; -FP ( -- addr ) marker -FP
hdr 1,'-FP',,1
dfp: call drop
; FLOAT+ ( f-addr1 -- f-addr2 ) 4 +
hdr 1,'FLOAT+'
floatp: pop ax
add ax,fw
jmp apush
; FLOATS ( n1 -- n2 ) 4 *
hdr 1,'FLOATS'
floats: pop ax
shl ax,1
shl ax,1
jmp apush
; FALIGN ( -- ) aka noop falign immediate
hdr 1,'FALIGN',1,,noop
falign equ next
; FALIGNED ( addr -- f-addr ) aka noop faligned immediate
hdr 1,'FALIGNED',1,,noop
falignd equ next
if fstack
cseg
; pop fp-stack to CX,DX
fpop: mov bx,fspp
mov cx,[bx]
mov dx,[bx+2]
add word ptr fspp,fw
ret
; push CX,DX to fp-stack
fpush: sub word ptr fspp,fw
mov bx,fspp
mov [bx],cx
mov [bx+2],dx
ret
; FLITERAL runtime
flit: lodsw
mov cx,ax
lodsw
mov dx,ax
call fpush
nextt
; FCONSTANT runtime
dofcon: pop bx
mov cx,[bx]
mov dx,[bx+2]
call fpush
nextt
else
flit equ tlit
dofcon equ tat
endif ;fstack
; F, (F: r -- ) or ( r -- )
hdr 1,'F,',,1
fcomm: call docol
dw here
dw clit
db fw
dw allot
dw fstor
dw exit
; FLITERAL ( -- r ) postpone flit f, ;immediate
hdr 1,'FLITERAL',1,1
flite: call docol
dw comp,flit
dw fcomm
dw exit
; FCONSTANT ( -- r )
hdr 1,'FCONSTANT',,1
fcon: call docol
dw lit,dofcon
dw build
dw fcomm
dw exit
; FVARIABLE ( -- f-addr ) aka 2variable fvariable
hdr 1,'FVARIABLE',,,tvar
fvar equ tvar
; FDEPTH ( -- +n ) fs0 @ fsp @ - 2/ 2/
hdr 1,'FDEPTH'
fdepth: call docol
if fstack
dw fszero,at
dw fsp,at
dw subb
dw twodiv
else
dw depth
endif
dw twodiv
dw exit
; FDROP ( r -- )
if fstack
hdr 1,'FDROP'
fdrop: add word ptr fspp,fw
nextt
else
hdr 1,'FDROP',,,tdrop ; aka 2drop fdrop
fdrop equ tdrop
endif
; FDUP ( r -- r r )
if fstack
hdr 1,'FDUP'
fdup: xchg fspp,sp
mov bx,sp
push [bx+2]
push [bx]
xchg fspp,sp
nextt
else
hdr 1,'FDUP',,,tdup ; aka 2dup fdup
fdup equ tdup
endif
; FSWAP ( r1 r2 -- r2 r1 )
if fstack
hdr 1,'FSWAP'
fswap: mov bx,fspp
mov ax,[bx]
xchg ax,[bx+4]
mov [bx],ax
mov ax,[bx+2]
xchg ax,[bx+6]
mov [bx+2],ax
nextt
else
hdr 1,'FSWAP',,,tswap ; aka 2swap fswap
fswap equ tswap
endif
; FOVER ( r1 r2 -- r1 r2 r1 )
if fstack
hdr 1,'FOVER'
fover: xchg fspp,sp
mov bx,sp
push [bx+6]
push [bx+4]
xchg fspp,sp
nextt
else
hdr 1,'FOVER',,,tover ; aka 2over fover
fover equ tover
endif
; FROT ( r1 r2 r3 -- r2 r3 r1 )
if fstack
hdr 1,'FROT'
frot: mov bx,fspp
mov ax,[bx]
xchg ax,[bx+4]
xchg ax,[bx+8]
mov [bx],ax
mov ax,[bx+2]
xchg ax,[bx+6]
xchg ax,[bx+10]
mov [bx+2],ax
nextt
else
hdr 1,'FROT',,,trot ; aka 2rot frot
frot equ trot
endif
; F@ ( f-addr -- r )
if fstack
hdr 1,'F@'
fat: pop bx
mov cx,[bx]
mov dx,[bx+2]
call fpush
nextt
else
hdr 1,'F@',,,tat ; aka 2@ f@
fat equ tat
endif
; F! ( r f-addr -- )
if fstack
hdr 1,'F!'
fstor: call fpop
pop bx
mov [bx],cx
mov [bx+2],dx
nextt
else
hdr 1,'F!',,,tstor ; aka 2! f!
fstor equ tstor
endif
; FPICK ( +n -- r ) floats sp@ cell+ + f@
hdr 1,'FPICK'
fpick: call docol
dw floats
if fstack
dw fsp,at
else
dw spat,cellp
endif
dw plus,fat
dw exit
cseg
; floating point accumulator
acce db 5 dup (?) ; exponent
accs = acce+1 ; sign
acc1 = accs+1 ; 1st fraction (msb)
acc2 = acc1+1 ; 2nd fraction
acc3 = acc2+1 ; 3rd fraction
sf db ? ; subtraction flag
f1 dd ? ; temp float storage
f2 dd ? ;
f3 dd ? ;
ften: call dofcon
fp10 db 84h,20h,0,0 ; 10.0
; save/load temp fp registers
savf1: mov bx,offset f1 ; save regs to f1
jmp short stom
savf2: mov bx,offset f2 ; save regs to f2
jmp short stom
lodf1: mov bx,offset f1 ; load accum/regs from f1
jmp short lod
lodf2: mov bx,offset f2 ; load accum/regs from f2
jmp short lod
; pop float from stack to accum
ldop:
if fstack
call fpop
mov bx,offset f1
mov [bx],cx
mov [bx+2],dx
else
pop dx
pop word ptr f1
pop word ptr f1+2
push dx
mov bx,offset f1
endif
jmp short lod
; pop 2 float from stack to bx (f2) and accum
ld2op:
if fstack
call fpop
mov bx,offset f2
push bx
mov [bx],cx
mov [bx+2],dx
call ldop
pop bx
else
pop di
pop word ptr f2
pop word ptr f2+2
call ldop
push di
mov bx,offset f2
endif
ret
; push float registers to stack and exit
svop: mov dl,cl
mov cl,al
if fstack
call fpush
else
push dx
push cx
endif
nextt
; overflow - set regs to maximum, set cy
ovf: mov cx,7fffh
mov al,cl
mov dh,cl
stc
ret
; zero - set accum and regs to zero
zro: sub ax,ax
mov acce,al
mov cx,ax
mov dh,al
ret
; load float [bx] to accum and regs, set flags
; entry - bx=adr
; exit - cx:dh (packed), al=exp, flags set
lod: mov dl,[bx]
and dl,dl
jnz lod1
jmp short zro
lod1: mov ch,[bx+1]
mov cl,[bx+2]
mov dh,[bx+3]
mov al,ch
or ch,80h
xor al,ch
lod2: call storr
xor al,ch
jmp short tst1
; store regs to accum dl=exp
storr: mov bx,offset acce
mov [bx],dl
inc bx
; store regs to mem
; entry - bx=adr al=exp cx:dh (packed)
; exit - none
stom: mov [bx],al
stom1: mov [bx+1],ch
mov [bx+2],cl
mov [bx+3],dh
ret
; change sign of accumulator and again
; when calling routine completes
chss: call chs
pop bx
call bx
; change sign of accumulator
; entry - none
; exit - cx:dh (packed) al=exp flags set
chs: xor byte ptr accs,80h
; load regs from acc and test
lodr: mov bx,offset acce
mov dl,[bx] ; exp
or dl,dl
jz zro
mov al,[bx+1] ; accs
xor al,[bx+2] ; msb sign packed
mov cl,[bx+3]
mov dh,[bx+4]
; entry - al:cl:dh (packed) dl=exp
; exit - cx:dh (packed) al=exp flags set
tst1: mov ch,al
tst2: or al,1 ; test sign, clear Z C flags
tst3: mov al,dl
ret
; entry - al=exp
; exit - dl=exp Z=zero S=negative
tstr: mov dl,al
or al,al
jnz tstr1
ret
tstr1: mov al,ch
jmp tst2
; normalize and pack cx:dx
npack: or ch,ch
js fpack
call norm
js fpack
jmp zro ; underflow or zero
; pack cx:dx
fpack: call rondr ; round cx:dx
jnc tst1
jmp ovf
; compare regs with mem [bx], return S if regs < mem, Z if match
; bx preserved
fcmp: cmp byte ptr [bx],0
jz tstr ; mem=0 test regs sign
or al,al
mov dl,al
mov al,[bx+1]
not al
jz tst2 ; regs=0 test mem sign
xor al,ch
jns tstr1 ; signs differ
cmp dl,[bx]
jnz fcmp1
cmp ch,[bx+1]
jnz fcmp1
cmp cl,[bx+2]
jnz fcmp1
cmp dh,[bx+3]
jz tst3 ; regs = mem
fcmp1: rcr al,1 ; carry to sign
xor al,ch ; complement sign for neg values
jmp tst2
; right shift n bits
; entry - cx:dh al=count
; exit - cx:dx
shrr: sub dl,dl
shrr1: or al,al ; test for zero
jz shrr2
shr cx,1
rcr dx,1
dec al
jmp shrr1
shrr2: ret
; Complement cx:dx adjust accs, return sign flag
fcpl: xor byte ptr accs,80h ; change accum sign
neg cx ; complement fraction
neg dx
sbb cx,0
ret
; Normalize cx:dx adjust acce
; entry - cx:dx
; exit - cx:dx z=cx:dx=0 or acce=0 sign=underflow
norm: mov bl,32 ; max shift
norm1: or ch,ch
jnz norm3
xchg ch,cl
xchg cl,dh
xchg dh,dl
sub bl,8
jnz norm1
ret ; cx:dx = zero
norm2: dec bl ; shl until bit 31 set
shl dx,1
rcl cx,1
or ch,ch
norm3: jns norm2
mov al,bl ; adjust accum exp
sub al,32
mov bx,offset acce
add al,[bx]
mov [bx],al
jz norm4
rcr al,1 ; carry to sign
and al,al ; sign = underflow
norm4: ret
; Round the cx:dx registers, save to acc
; entry - cx:dx
; exit - cx:dh al=packed msb dl=exp cy=ovf
rondr: and dl,dl ; test bit 7 and clear cy
mov bx,offset acce ; exp
mov dl,[bx]
jns rondr1
inc dh ; round up cx:dh dl=exp
jnz rondr1
inc cx
jnz rondr1
mov ch,80h ; new 1st fraction
add dl,1 ; inc exp adjust cy
mov acce,dl ; new acc exp
rondr1: jc rondr2 ; overflow
mov al,ch
inc bx ; accs
xor al,[bx] ; a=packed msb
jmp stom1 ; save cx:dh to acc
rondr2: ret
; fsu floating point subtract subroutine
fsu: mov ch,80h ; mask to change operand sign
ignore2
; fad floating point add subroutine
fad: mov ch,0
mov dl,[bx] ; load operand
xor ch,[bx+1]
mov cl,[bx+2]
mov dh,[bx+3]
and dl,dl
jz fad2 ; operand zero
mov al,ch ; unpack
or ch,80h
xor al,ch ; generate subtraction flag
mov bx,offset accs
xor al,[bx]
mov sf,al
; determine relative magnitudes of operand and accum
dec bx
mov al,[bx] ; acce
or al,al
jz fad8 ; accum zero
sub al,dl ; get difference of exponents
jc fad3 ; accum smaller
; check insignificant operand
js fad2
cmp al,25 ; compare shift count to 25
jc fad4
fad2: jmp lodr
; check insignificant accum
fad3: jns fad8
cmp al,0-25 ; compare shift count to -25
jc fad8 ; move operand to accum
mov [bx],dl ; set acce
neg al ; complement shift count
mov dl,sf
xor [bx+1],dl ; set accs
xchg ch,[bx+2] ; exchange fraction
xchg cl,[bx+3]
xchg dh,[bx+4]
; position the operand, check if add or subtract
fad4: call shrr
mov bx,offset acc3
mov al,sf
or al,al
js fad6
add dh,[bx] ; add
adc cl,[bx-1]
adc ch,[bx-2]
jnc fad5
rcr cx,1 ; rshift fraction
rcr dx,1
add byte ptr acce,1 ; adjust exponent
jnc fad5
jmp ovf ; overflow
fad5: jmp fpack
fad6: neg dl ; subtract
mov al,[bx]
sbb al,dh
mov dh,al
mov al,[bx-1]
sbb al,cl
mov cl,al
mov al,[bx-2]
sbb al,ch
mov ch,al
jnc fad7
call fcpl ; complement
fad7: jmp npack
; move operand to accumulator
fad8: mov al,sf
mov bx,offset accs
xor al,[bx]
jmp lod2
; read the operand at (bx), check the accum exponent
mdex: mov ch,al
mov cl,[bx+1]
mov dh,[bx+2]
mov dl,[bx+3]
mov bx,offset acce ; accum exp
mov al,[bx]
or al,al
jz mdex2 ; is zero
add al,ch ; result exp plus bias
mov ch,al
rcr al,1 ; carry to sign
xor al,ch ; carry and sign must differ
mov al,ch ; result exp plus bias
mov ch,80h ; exp bias, sign mask, most sig bit
jns mdex1 ; if over or underflow
sub al,ch ; remove excess exp bias
jz mdex2 ; return if underflow
mov [bx],al ; result exp
inc bx ; address accum sign
xor [bx],cl ; result sign in sign bit
and [bx],ch ; result sign
mov al,cl ; operand sign and 1st fraction
or al,ch ; operand first fraction
ret
mdex1: rol al,1 ; set carry bit if overflow
jc mdex2
sub al,al ; clear register
mdex2: ret
; fixed point multiply subroutine al:dx * acc -> cx:dh
mulx: mov di,dx ; 3rd 2nd multiplicand
; multiply by each accumulator fraction in turn
sub ah,ah ; clear 6th product
sub dx,dx ; clear 4th 5th product
mov bx,offset acc3 ; multiply by accum 3rd fraction
call mulx2
mov bx,offset acc2 ; multiply by accum 2nd fraction
call mulx1
mov bx,offset acc1
; multiply by one accumulator byte
mulx1: mov ah,dh ; 5th partial product
mov dx,cx ; 3rd 4th partial prod
mulx2: mov ch,[bx] ; multiplier
sub cl,cl ; 2nd partial prod
cmp cl,ch ; set carry bit for exit flag
jc mulx4 ; if multiplier is zero
mov cl,dh ; 2nd partial product
mov dh,dl ; 3rd partial prod
mulx3: ret
; loop for each bit of multiplier byte
mulx4: adc ah,ah ; shift exit flag out if done
jz mulx3 ; exit if multiplication done
rcl dx,1 ; 4th 3rd partial prod
rcl cx,1 ; 2nd 1st partial prod
jnc mulx4 ; if addition required
; add the multiplicand to the product if the multiplier bit is one
add dx,di ; 4th 3rd partial prod
adc cl,al ; 2nd partial prod
adc ch,0 ; add carry to 1st prod
clc
jmp mulx4
; fmu floating point multiplication subroutine
fmu: mov al,[bx] ; operand exponent
or al,al
push bx
jz fmu1
call mdex ; read operand
fmu1: pop bx
jz fmu3 ; zero or underflow
jc fmu4 ; overflow
call mulx ; fixed mult
or ch,ch ; normalize if necessary
js fmu2
dec byte ptr acce ; dec accum exp
jz fmu3 ; underflow
shl dx,1
rcl cx,1
fmu2: jmp fpack
fmu3: jmp zro ; zero or underflow
fmu4: jmp ovf ; overflow
; fixed point divide
; entry - al:dx
; exit - cx:dx nc=overflow
; subtract divisor from accum to obtain 1st remainder
divx: mov bx,offset acc1
sub [bx+2],dl ; acc 3rd fraction
sbb [bx+1],dh ; acc 2nd fraction
sbb [bx],al ; acc 1st fraction
; halve divisor and store for addition or subtraction cl:dx:ch
sub ah,ah ; init quot 1st fraction
sar al,1 ; divisor 1st fraction
rcr dx,1 ; divisor 2nd 3rd fraction
rcr ah,1 ; divisor 4th fraction is zero
mov di,dx
; load 1st remainder
mov dl,[bx] ; 1st fraction
mov bx,[bx+1] ; 2nd 3rd fraction
xchg bh,bl
; position remainder, initialise quotient, check sign
sub cx,cx ; init quot 2nd fraction
sub dh,dh ; init quot 3rd fraction
or dl,dl ; test sign, clear cy
js divx5 ; remainder negative
inc byte ptr acce ; inc quotient exponent
jnz divx1
ret ; overflow
divx1: inc dh ; init quot 3rd fraction
; sub divisor if remainder positive
divx2: neg ah ; 4th fraction is zero
neg ah
sbb bx,di ; 2nd 3rd fraction
sbb dl,al ; 1st fraction
divx3: rol ch,1 ; shift remainder left one bit
ror ch,1
jnc divx4
ret ; division complete
divx4: rol ah,1 ; shift remainder 4th fraction to carry
ror ah,1
rcl bx,1 ; shift cx:dx:bx
rcl dx,1
rcl cx,1
; branch if subtraction is required
ror dh,1 ; quotient 3rd fraction
rol dh,1 ; remainder sign to carry bit
jc divx2 ; to sub divisor if remainder positive
; add divisor if remainder negative
divx5: add bx,di ; 2nd 3rd fraction
adc dl,al ; 1st fraction
jmp divx3
; fdi floating point division subroutine
fdi: sub al,al
sub al,[bx] ; complement of divisor exponent
cmp al,1 ; set carry if division by zero
push bx
jc fdi1
call mdex ; read operand if not zero
fdi1: pop bx
jc fdi2
jz fdi3
call divx ; fixed division
jnc fdi2
jmp fpack
fdi2: jmp ovf ; overflow or division by zero
fdi3: jmp zro ; underflow or zero
; convert signed integer AL to float
flta: mov ch,al
sub cl,cl
sub dx,dx
mov al,8
ignore2
; convert 32 bit signed integer to float
; entry - cx:dx (int)
flt: mov al,32 ; scaling factor
xor al,80h ; apply exponent bias
mov bx,offset acce
mov [bx],al
mov byte ptr [bx+1],80h ; assume positive
or ch,ch
jns flt2
call fcpl ; negate
flt2: jmp npack
; fix convert float in acc to 32 bit signed integer
; exit - cx:dx (int) cy=overflow
fix: mov dl,32 ; scaling
or al,al
jz fix2 ; zero
xchg dl,al
add al,80h-1 ; add bias-1
sub al,dl ; shift count -1
jc fix1 ; accum too large
cmp al,31 ; compare to large shift
jnc fix2 ; accum too small
inc al ; shift count
or ch,80h ; unpack msb
call shrr ; position the fraction
test byte ptr accs,80h
js fix1
call fcpl
fix1: clc
ret
fix2: sub cx,cx ; zero
sub dx,dx
ret
; Round/floor/trunc accum to integer
; entry - al cx:dh
; exit - al cx:dh dl=signed integer
flr: mov bl,1 ; mode
flr1: or al,al
jz flr6 ; zero
mov dl,dh
mov ah,80h+24
cmp al,ah
jnc flr5 ; no fraction
mov acce,ah
mov bh,ch ; save sign
xor bh,bl ; adjust for mode
or ch,80h ; unpack msb
test bl,1
jz flr2
or bh,bh
jns flr2
sub dh,1 ; dec cx:dh
sbb cx,0
flr2: neg al
add al,ah
call shrr
test bl,1
jz flr3
or bh,bh
jns flr3
add dh,1 ; inc cx:dh
adc cx,0
flr3: or bl,bl
jnz flr4
add dl,dl ; round
adc dh,0
adc cx,0
flr4: push dx
sub dl,dl
call npack ; normalize and pack
pop bx
mov dl,bh
flr5: or ch,ch
jns flr6
neg dl
flr6: ret
; FABS (F: r1 -- r2 ) or ( r1 -- r2 )
hdr 1,'FABS'
fabss:
if fstack
mov bx,fspp
else
mov bx,sp
endif
and byte ptr [bx+1],7fh
nextt
; FNEGATE ( r1 -- r2 )
hdr 1,'FNEGATE'
fneg:
if fstack
mov bx,fspp
else
mov bx,sp
endif
xor byte ptr [bx+1],80h
nextt
; D>F ( d -- r )
hdr 1,'D>F'
dtof: pop cx
pop dx
call flt
jmp svop
; F>D ( r -- d )
hdr 1,'F>D'
ftod: call ldop
call fix
jnc ftod1
jmp cverr ; overflow
ftod1: push dx
push cx
nextt
; S>F ( n -- r ) s>d d>f
hdr 1,'S>F'
stof: call docol
dw stod,dtof
dw exit
; F>S ( r -- n ) f>d d>s
hdr 1,'F>S'
ftos: call docol
dw ftod,dtos
dw exit
; F0= ( r -- flag )
hdr 1,'F0='
fze: call ldop
fze1: jnz ffl
jmp true
ffl: jmp false
if fpx
; F= ( r1 r2 -- flag )
hdr 1,'F='
feq: call ld2op
call fcmp
jmp fze1
endif
; F0< ( r -- flag )
hdr 1,'F0<'
fzl: call ldop
fzl1: jns ffl
jmp true
; F< ( r1 r2 -- flag )
hdr 1,'F<'
fles: call ld2op
call fcmp
jmp fzl1
; F0> ( r -- flag )
hdr 1,'F0>'
fzg: call ldop
fzg1: jz ffl
js ffl
jmp true
; F> ( r1 r2 -- flag )
hdr 1,'F>'
fgre: call ld2op
call fcmp
jmp fzg1
; FMIN ( r1 r2 -- r3 )
hdr 1,'FMIN'
fmin: call ld2op
call fcmp
js fmin1
call lod ; r1 >= r2
fmin1: jmp svop
; FMAX ( r1 r2 -- r3 )
hdr 1,'FMAX'
fmax: call ld2op
call fcmp
jns fmax1
call lod ; r1 < r2
fmax1: jmp svop
; FLOOR ( r1 -- r2 )
hdr 1,'FLOOR'
floor: call ldop
call flr
jmp svop
; FROUND ( r1 -- r2 )
hdr 1,'FROUND'
frnd: call ldop
mov bl,0
frnd1: call flr1
jmp svop
if fpx
; FTRUNC ( r1 -- r2 )
hdr 1,'FTRUNC'
ftrunc: call ldop
mov bl,2
jmp frnd1
; FCEIL ( r1 -- r2 )
hdr 1,'FCEIL'
fceil: call ldop
mov bl,-1
jmp frnd1
endif
; F+ ( r1 r2 -- r3 )
hdr 1,'F+'
faddd: call ld2op
call fad
jmp svop
; F- ( r1 r2 -- r3 )
hdr 1,'F-'
fsubb: call ld2op
call fsu
jmp svop
; F* ( r1 r2 -- r3 )
hdr 1,'F*'
fstar: call ld2op
call fmu
jmp svop
; F/ ( r1 r2 -- r3 )
hdr 1,'F/'
fslas: call ld2op
call fdi
jmp svop
; FRANDOM ( r1 -- r2 )
hdr 1,'FRANDOM'
rand: call ldop
js rand1 ; neg = seed generator
pushf
mov bx,offset rand5
call lod
popf
jz rand2 ; zero = return last value
mov bx,offset rand3 ; pos = get next value
call fmu
mov bx,offset rand4
call fad
rand1: mov bx,offset acc3
mov ch,[bx] ; swap msb lsb
mov cl,[bx-1]
mov dh,[bx-2]
mov byte ptr [bx-3],80h ; make positive
mov dl,[bx-4]
mov byte ptr [bx-4],80h ; fix exponent
call npack ; normalize
mov bx,offset rand5
call stom
rand2: jmp svop
rand3 db 98h,35h,44h,7Ah
rand4 db 68h,28h,0B1h,46h
rand5 db 80h,31h,41h,59h ; seed
cseg
finstr dw ?,? ; string addr, count
finsgn db ? ; sign
finpt db ? ; decimal point flag
finexp db ? ; decimal exponent
fincvt db ? ; converted digits
; fin convert character string to float
; entry - bx=adr, ax=len
; exit - result in accum, cy=error
fin: dec bx ; init string adr, count
inc ax
mov finstr,bx
mov finstr+2,ax
mov finsgn,80h ; set sign positive
xor al,al
mov finpt,al ; clear decimal point flag
mov finexp,al ; set decimal exponent = 0
mov fincvt,al ; zero converted digits
mov acce,al ; zero accum
call fin21 ; get 1st char
jz fin7 ; treat zero length as blanks
cmp al,' '
jnz fin2
fin1: call fin21 ; treat all blanks as zero
jz fin7
cmp al,' '
jz fin1
stc
ret
fin2: cmp al,'+' ; check for sign
jz fin3
cmp al,'-'
jnz fin4
mov finsgn,0 ; set negative flag
fin3: call fin21 ; get char after sign
jz fin5 ; none
fin4: cmp al,'.' ; check for decimal point
jnz fin8
xor finpt,-1 ; 2nd decimal point?
jnz fin9
fin5: stc ; error
ret
fin6: cmp fincvt,0
jz fin5
fin7: jmp short fin16
; process char
fin8: call fin22 ; convert char to digit
jc fin5 ; bad
inc fincvt
push ax
mov bx,offset fp10 ; mult old value by 10
call fmu
call savf1
pop ax
call flta ; convert digit to floating point
mov bx,offset f1 ; add to old value
call fad
mov al,finpt ; if decimal point
add finexp,al ; decrement exponent
; get next char
fin9: mov ch,0 ; zero exponent
call fin21
jz fin6 ; done
; check for exponent
cmp al,'+'
jz fin11
cmp al,'-'
jz fin11
call upc
cmp al,'E'
jz fin10
cmp al,'D'
jnz fin4
; process exponent
fin10: call fin21 ; next char
jz fin6 ; done
fin11: mov dl,al
sub dl,'-' ; test minus sign
jz fin12
cmp dl,'+'-'-' ; test plus sign
jnz fin13
fin12: call fin21 ; got sign, get 1st digit
fin13: mov ch,0 ; possible decimal exponent
; jnz fin14
; jmp fin5 ; none - error
jz fin6 ; none - assume zero exponent
fin14: call fin22
jnc fin15
ret ; not digit
fin15: mov cl,10 ; accumulate exponent
xchg cl,al
mul ch
add al,cl
mov ch,al
call fin21 ; get next
jnz fin14
and dl,dl ; test exponent sign
jnz fin16
neg ch ; complement if neg
fin16: mov al,finsgn ; store accum sign
mov accs,al
; adjust exponent
fin17: mov bx,offset finexp
add ch,[bx]
jnz fin18
jmp lodr ; done
fin18: mov [bx],ch
mov bx,offset fp10
jns fin19
call fdi ; div by 10
mov ch,1
jmp fin17
fin19: call fmu ; mul by 10
jnc fin20
ret ; overflow
fin20: mov ch,-1
jmp fin17
; get next char al return z if end
fin21: mov bx,offset finstr
inc word ptr [bx]
dec word ptr [bx+2]
mov bx,[bx]
mov al,[bx]
ret
; convert ascii char (a) to digit, return cy if not in range 0-9
fin22: sub al,'0'
jc fin23
cmp al,10
cmc
fin23: ret
; >FLOAT ( c-addr u -- r true | false )
hdr 1,'>FLOAT'
tflt: pop ax
pop bx
call fin
jc tflt1
mov dl,cl
mov cl,al
if fstack
call fpush
else
push dx
push cx
endif
jmp true
tflt1: jmp false
hdr 1,'MAX-PRECISION'
mprec: call docco ; max precision
db maxsig
hdr x,'EXSN'
exsn: call docre ; exponent, sign
dw 2 dup (?)
; REPRESENT ( r c-addr n -- exp sign flag )
; 2dup max-precision max [char] 0 fill
; max-precision min 2>r fdup f0< 0 exsn 2!
; fabs fdup f0= 0= if begin fdup 1.0e f<
; 0= while 10.0e f/ 1 exsn +! repeat begin
; fdup 0.1e f< while 10.0e f* -1 exsn +!
; repeat then r@ 0 max 0 ?do 10.0e f* loop
; fround f>d 2dup <# #s #> dup r@ - exsn +!
; 2r> rot min 1 max cmove d0= if 1 0 else
; exsn 2@ swap then true
hdr 1,'REPRESENT'
repr: call docol
dw tdup
dw mprec,max
dw clit
db '0'
dw fill
dw mprec,min
dw ttor
dw fdup,fzl
dw zero,exsn,tstor
dw fabss
dw fdup,fze
dw zequ
dw zbran,repr3
repr1 dw fdup ; begin
dw flit
db 81h,0,0,0
dw fles,zequ
dw zbran,repr2 ; while
dw ften,fslas
dw one,exsn,pstor
dw bran,repr1 ; repeat
repr2 dw fdup ; begin
dw flit
db 7dh,4ch,0cch,0cdh
dw fles
dw zbran,repr3 ; while
dw ften,fstar
dw true,exsn,pstor
dw bran,repr2 ; repeat
repr3 dw rat
dw zero,max,zero
dw xqdo,repr5
repr4 dw ften,fstar
dw xloop,repr4
repr5 dw frnd,ftod
dw tdup
dw bdigs,digs,edigs
dw dupp
dw rat,subb ; handle overflow
dw exsn,pstor
dw tfrom
dw rot,min
dw one,max
dw cmove
dw dzequ
dw zbran,repr6
dw one,zero ; 0.0E fixup
dw bran,repr7
repr6 dw exsn,tat
dw swap
repr7 dw true
dw exit
; PRECISION ( -- u )
hdr 1,'PRECISION'
prec: call doval
dw ? ; set by FPINIT
; SET-PRECISION ( u -- ) 1 max max-precision min to precision
hdr 1,'SET-PRECISION'
setpr: call docol
dw one,max
dw mprec,min
dw pto,prec
dw exit
hdr 1,'FDP'
fdp: call docre ; decimal point display
dw ?,? ; set by FPINIT
hdr x,'FBUF'
fbuf: call docre ; fp string buffer
db maxsig dup (?)
hdr x,'EX#'
exn: call doval ; exponent
dw ?
hdr x,'SN#'
snn: call doval ; sign
dw ?
hdr x,'EF#'
efn: call doval ; exponent factor
dw ?
hdr x,'PL#'
pln: call doval ; places after decimal point
dw ?
; (f1) ( r -- r exp )
; fdup fbuf max-precision represent 2drop
hdr x,'(F1)' ; get exponent
pf1: call docol
dw fdup
dw fbuf,mprec
dw repr,tdrop ; never error
dw exit
; (f2) ( exp -- offset exp' ) s>d ef# fm/mod ef# *
hdr x,'(F2)' ; apply exponent factor
pf2: call docol
dw stod
dw efn,fmmod
dw efn,star
dw exit
; (f3) ( r places -- c-addr u )
; dup to pl# 0< if precision else (f1) ef# 0>
; if 1- (f2) drop 1+ then pl# + max-precision
; min then fbuf swap represent drop to sn# to
; ex# fbuf max-precision -trailing <# ;
hdr x,'(F3)' ; float to ascii
pf3: call docol
dw dupp
dw pto,pln
dw zless
dw zbran,pf31
dw prec
dw bran,pf33
pf31 dw pf1
dw efn,zgrea
dw zbran,pf32
dw onem
dw pf2,drop
dw onep
pf32 dw pln,plus
dw mprec,min
pf33 dw fbuf,swap
dw repr
dw drop ; never error
dw pto,snn
dw pto,exn
dw fbuf
dw mprec
dw dtrai
dw bdigs
dw exit
; (f4) ( exp -- ) pl# 0< >r dup abs s>d r@ 0= if # then #s
; 2drop dup sign 0< r> d0= if [char] + hold
; then [char] E hold
hdr x,'(F4)' ; insert exponent
pf4: call docol
dw pln,zless
dw tor
dw dupp
dw abss,stod
dw rat,zequ
dw zbran,pf41
dw dig
pf41 dw digs
dw tdrop
dw dupp,sign
dw zless
dw fromr
dw dzequ
dw zbran,pf42
dw clit
db '+'
dw hold
pf42 dw clit
db 'E'
dw hold
dw exit
; (f5) ( n -- +n|0 ) 0max dup fdp 2+ +!
hdr x,'(F5)' ; conditionally set flag
pf5: call docol
dw zmax
dw dupp
dw fdp,twop
dw pstor
dw exit
; (f6) ( c-addr u -- ) (f5) shold
hdr x,'(F6)' ; insert string
pf6: call docol
dw pf5,shold
dw exit
; (f7) ( n -- ) (f5) [char] 0 nhold
hdr x,'(F7)' ; insert '0's
pf7: call docol
dw pf5
dw clit
db '0'
dw nhold
dw exit
; (f8) ( -- ) sn# sign 0 0 #>
hdr x,'(F8)' ; insert sign
pf8: call docol
dw snn,sign
dw zero,zero
dw edigs
dw exit
; (f9) ( c-addr u1 -- c-addr u2 ) pl# 0< if [char] 0 trim then
hdr x,'(F9)' ; trim trailing '0's
pf9: call docol
dw pln,zless
dw zbran,pf91
dw clit
db '0'
dw trim
pf91 dw exit
; (fa) ( u1 -- u1 u2 ) pl# 0< if dup else pl# then
hdr x,'(FA)'
pfaa: call docol
dw pln,zless
dw zbran,pfaa1
dw dupp
dw bran,pfaa2
pfaa1 dw pln
pfaa2 dw exit
; (fb) ( c-addr u n -- ) fdp cell+ off >r (f9) r@ + (fa) over -
; (f7) (fa) min r@ - (f6) r> (fa) min (f7)
; fdp 2@ or if [char] . hold then
hdr x,'(FB)' ; insert fraction n places right of dec. pt
pfbb: call docol
dw fdp,twop
dw off
dw tor
dw pf9
dw rat,plus
dw pfaa
dw over,subb
dw pf7
dw pfaa,min
dw rat,subb
dw pf6
dw fromr
dw pfaa,min
dw pf7
dw fdp,tat,orr
dw zbran,pfbb1
dw clit
db '.'
dw hold
pfbb1 dw exit
; (fc) ( c-addr u n -- )
; >r 2dup r@ min 2swap r> /string 0 (fb) (f6)
hdr x,'(FC)' ; split into int/frac and insert
pfcc: call docol
dw tor
dw tdup
dw rat,min
dw tswap
dw fromr,sstr
dw zero,pfbb
dw pf6
dw exit
; (fd) ( r n factor -- c-addr u )
; to ef# (f3) ex# 1- (f2) (f4) 1+ (fc) (f8)
hdr x,'(FD)' ; exponent form
pfdd: call docol
dw pto,efn
dw pf3
dw exn,onem
dw pf2
dw pf4
dw onep,pfcc
dw pf8
dw exit
; (FS.) ( r n -- c-addr u ) 1 (fd)
hdr 1,'(FS.)'
pfsd: mov ax,1
push ax
jmp pfdd
; FS.R ( r n1 n2 -- ) >r (fs.) r> s.r
hdr 1,'FS.R'
fsdr: call docol
dw tor
dw pfsd
dw bran,ddotr1
; FS. ( r -- ) -1 0 fs.r space
hdr 1,'FS.'
fsdot: call docol
dw true
dw zero,fsdr
dw space
dw exit
if fpeng
; (FE.) ( r -- c-addr u ) 3 (fd)
hdr 1,'(FE.)'
pfse: mov ax,3
push ax
jmp pfdd
; FE.R ( r n1 n2 -- ) >r (fe.) r> s.r
hdr 1,'FE.R'
fedr: call docol
dw tor
dw pfse
dw bran,ddotr1
; FE. ( r -- ) -1 0 fe.r space
hdr 1,'FE.'
fedot: call docol
dw true
dw zero,fedr
dw space
dw exit
endif
; (F.) ( r n -- c-addr u )
; 0 to ef# (f3) ex# dup max-precision > if
; fbuf 0 0 (fb) max-precision - (f7) (f6)
; else dup 0> if (fc) else abs (fb) 1 (f7)
; then then (f8)
hdr 1,'(F.)'
pfd: call docol
dw zero
dw pto,efn
dw pf3
dw exn,dupp
dw mprec,great
dw zbran,pfd1 ; if
dw fbuf,zero
dw zero,pfbb
dw mprec,subb
dw pf7
dw pf6
dw bran,pfd3 ; else
pfd1 dw dupp,zgrea
dw zbran,pfd2
dw pfcc
dw bran,pfd3 ; else
pfd2 dw abss
dw pfbb
dw one,pf7
pfd3 dw pf8 ; then then
dw exit
; F.R ( r n1 n2 -- ) >r (f.) r> s.r
hdr 1,'F.R'
fdotr: call docol
dw tor
dw pfd
dw bran,ddotr1
; F. ( r -- ) -1 0 f.r space
hdr 1,'F.'
fdot: call docol
dw true
dw zero,fdotr
dw space
dw exit
; (G.) ( r n -- c-addr u )
; >r (f1) -3 7 within r> swap if (f.) else
; (fs.) then
hdr 1,'(G.)'
pgd: call docol
dw tor
dw pf1
dw lit,-3
dw clit
db 7
dw within
dw fromr,swap
dw zbran,pgd1 ; if
dw pfd
dw bran,pgd2 ; else
pgd1 dw pfsd
pgd2 dw exit ; then
; G.R ( r n1 n2 -- ) >r (g.) r> s.r
hdr 1,'G.R'
gdotr: call docol
dw tor
dw pgd
dw bran,ddotr1
; G. ( r -- ) -1 0 g.r space
hdr 1,'G.'
gdot: call docol
dw true
dw zero,gdotr
dw space
dw exit
cseg
; sqr
sqr: call tstr
jnz sqr1
ret ; zero
sqr1: jns sqr2
jmp ovf ; neg
sqr2: call savf1
and al,al
rcr al,1
add al,40h
call savf2
mov dh,5
sqr3: push dx
call lodf1
mov bx,offset f2
call fdi
mov bx,offset f2
call fad
sub al,1
call savf2
pop dx
dec dh
jnz sqr3
mov bx,offset f2
jmp lod
; poly
poly: push bx
call savf1
pop bx
mov al,[bx]
mov poly3,al
inc bx
push bx
call lod
jmp short poly2
poly1: push bx
mov bx,offset f1
call fmu
pop bx
push bx
call fad
poly2: pop bx
add bx,fw
dec byte ptr poly3
jnz poly1
ret
poly3 db ?
; polx
polx: push bx
call savf2
mov bx,offset f2
call fmu
pop bx
call poly
mov bx,offset f2
jmp fmu
; exp
exp: mov bx,offset ln2
call fdi
cmp al,88h
jnc exp3
cmp al,68h
jnc exp1
mov bx,offset fp1
jmp lod
exp1: call savf2
call flr
call savf1
mov al,dl
add al,81h
jz exp2
push ax
call lodf2
mov bx,offset f1
call fsu
mov bx,offset exp4
call poly
pop ax
mov cx,0
mov dh,ch
call savf1
mov bx,offset f1
jmp fmu
exp2: call lodr
jns exp3
jmp zro
exp3: jmp ovf
exp4 db 7
db 74h,59h,88h,7ch
db 77h,26h,97h,0e0h
db 7ah,1eh,1dh,0c4h
db 7ch,63h,50h,5eh
db 7eh,75h,0feh,1ah
ln2 db 80h,31h,72h,18h ; ln2
fp1 db 81h,0,0,0 ; 1.0
; log
log: call tstr
jng log1 ; neg or zero
xor al,80h
push ax
mov al,80h
mov bx,offset log2
call poly
call savf1
pop ax
call flta
mov bx,offset f1
call fad
mov bx,offset ln2
jmp fmu
log1: jmp zro
log2 db 9
db 82h,94h,0eeh,0d8h
db 84h,7dh,0aah,0a9h
db 86h,0bfh,99h,7dh
db 87h,28h,0e5h,7bh
db 87h,0c0h,71h,8ah
db 87h,14h,95h,6eh
db 86h,0a0h,1eh,0b2h
db 85h,02h,7ah,0adh
db 83h,8dh,9dh,09h
; sin / cos
cos: mov bx,offset fpi2
call fad
sin: or al,al
jnz sin1
ret
sin1: cmp al,80h+25
jc sin2
jmp ovf
sin2: mov bx,offset f2pi
call fdi
call savf1
call flr
or al,al
pushf
jz sin3
call savf2
sin3: call lodf1
popf
jz sin4
mov bx,offset f2
call fsu
sin4: mov bx,offset fp25 ; 0.25
call fsu
pushf
js sin5
mov bx,offset fp50 ; 0.5
call fsu
js sin5
call chs
sin5: mov bx,offset fp25 ; 0.25
call fad
popf
js sin6
call chs
sin6: mov bx,offset sin7
jmp polx
sin7 db 5
db 86h,1eh,0d7h,0fbh
db 87h,99h,26h,64h
db 87h,23h,34h,58h
db 86h,0a5h,5dh,0e1h
f2pi db 83h,49h,0fh,0dbh ; 2pi
fpi2 db 81h,49h,0fh,0dbh ; pi/2
fp50 db 80h,0,0,0 ; 0.5
fp25 db 7fh,0,0,0 ; 0.25
; atan
atan: call tstr
jns atan1
call chss ; make positive
atan1: cmp al,81h
jc atan2 ; < 1
mov bx,offset atan4
push bx
call savf1
mov bx,offset fp1
call lod
mov bx,offset f1
call fdi
atan2: mov bx,offset atan9
call fcmp
js atan3
mov bx,offset atan5
push bx
call savf1
mov bx,offset atan7
call fad
mov bx,offset f3
call stom
call lodf1
mov bx,offset atan6
call poly
mov bx,offset f3
call fdi
atan3: mov bx,offset atan8
jmp polx
atan4: mov bx,offset fpi2
call fsu
jmp chs
atan5: mov bx,offset atan10
jmp fad
atan6 db 2
atan7 db 81h,5dh,0b3h,0d7h
db 81h,80h,0,0 ; -1.0
atan8 db 4
db 7eh,83h,35h,62h
db 7eh,4ch,24h,50h
db 7fh,0aah,0a9h,79h
db 81h,0,0,0
atan9 db 7fh,09h,38h,0a3h
atan10 db 80h,06h,0ah,92h
; FSQRT ( r1 -- r2 )
hdr 1,'FSQRT'
fsqr: call ldop
call sqr
jmp svop
; FEXP ( r1 -- r2 )
hdr 1,'FEXP'
fexp: call ldop
call exp
jmp svop
; FLN ( r1 -- r2 )
hdr 1,'FLN'
ffln: call ldop
call log
jmp svop
; F** ( r1 -- r2 ) fswap fln f* fexp
hdr 1,'F**'
fsq: call docol
dw fswap,ffln
dw fstar,fexp
dw exit
; FSIN ( r1 -- r2 )
hdr 1,'FSIN'
fsinn: call ldop
call sin
jmp svop
; FCOS r1 -- r2 )
hdr 1,'FCOS'
fcoss: call ldop
call cos
jmp svop
; FATAN ( r1 -- r2 )
hdr 1,'FATAN'
fatan: call ldop
call atan
jmp svop
; PI ( -- r )
hdr 1,'PI'
fpi: call dofcon
db 82h,49h,0fh,0dbh ; pi
; fpinit ( -- ) max-precision set-precision fdp on
hdr x,'FPINIT'
fpini: call docol
dw mprec,setpr
dw fdp,on
dw exit
; fident ( -- )
hdr x,'FIDENT',,1
fiden: call docol
dw crr
dw pdotq
db fiden1-$-1
db 'Software floating-point ('
if fstack
db 'separate'
else
db 'common'
endif
db ' stack)'
fiden1 dw exit
if not ldp ; F94 requires digit before decimal-point
; fnumber ( c-addr u -- [r] flag )
; dup 1 > if over dup c@ [char] . < - c@
; [char] . > >r 2dup s" E" caps search -rot
; 2drop r> and decimal? and 0= while then
; 2drop 0 else >float then dup >r state?
; and if postpone fliteral then r>
hdr x,'FNUMBER',,1
fnumb: call docol
dw dupp,one,great
dw zbran,fnumb1
dw over
dw dupp,cat
dw clit
db '.'
dw less,subb ; skip sign
dw cat
dw clit
db '.'
dw great ; digit?
dw tor
dw tdup ; scan 'E'
dw psqot
dcs 'E'
if ucase
dw caps
endif
dw sear
dw drot,tdrop
dw fromr,andd
dw dcmq ; decimal base?
dw andd,zequ
dw zbran,fnumb2
fnumb1 dw tdrop,zero
dw bran,fnumb3
fnumb2 dw tflt
fnumb3 dw dupp,tor
dw stateq
dw andd
dw zbran,fnumb4
dw flite
fnumb4 dw fromr
dw exit
else ; allow leading decimal-point
; fnumber ( c-addr u -- [r] flag )
; 2dup s" E" caps search -rot 2drop decimal?
; and if >float else 2drop 0 then dup >r
; state? and if postpone fliteral then r>
hdr x,'FNUMBER',,1
fnumb: call docol
dw tdup ; scan 'E'
dw psqot
dcs 'E'
if ucase
dw caps
endif
dw sear
dw drot,tdrop
dw dcmq ; decimal base?
dw andd
dw zbran,fnumb2
fnumb1 dw tflt
dw bran,fnumb3
fnumb2 dw tdrop,zero
fnumb3 dw dupp,tor
dw stateq
dw andd
dw zbran,fnumb4
dw flite
fnumb4 dw fromr
dw exit
endif
aseg
; ( -- ) :noname ['] noop dup (pinit) ! (piden) !
; ['] false (pfnum) ! (nfps) off (nfpm) off
; ; remember
hdr x,'(-FP)',,1
fprun: mov ax,offset noop
mov word ptr pinit,ax ; INIT
mov word ptr piden,ax ; INDENTIFY
mov ax,offset false
mov word ptr pfnum,ax ; FNUMBER
sub ax,ax
mov nfps,ax
mov nfpm,ax
nextt
fprun1 dw 0 ; link
dw fprun ; xt
endif ; float
topnfa equ lnk-horig ; nfa of top word in forth vocab
topxt equ cfadr ; xt of top word in forth vocab
cseg
initdp equ $
aseg
initdps equ $
heads segment public
initdph equ $-horig
heads ends
cseg
; Move heads into place for .COM executable only.
; Assumes heads located entirely in DS segment.
; Code is run once then disabled.
; MOVE-PATCH ( -- )
movpat: mov es,hseg1 ; ES = headers segment
mov cx,idph ; move heads
mov di,cx
dec di
mov si,di
add si,idps
std
rep movsb
cld
mov word ptr cldd6,0CF8Bh ; change 'MOV CX,DI'
mov word ptr cldd7,0F929h ; change 'SUB CX,DI'
mov word ptr cldd9,cold-cldd9-2 ; patch myself out
jmp cold
main ends
end start ; start address
; End