pcs/sinterp.asm

3213 lines
133 KiB
NASM
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; =====> SINTERP.ASM
;******************************************************************************
;* TIPC Scheme '84 Runtime Support *
;* Interpreter *
;* *
;* (C) Copyright 1984,1985,1986,1987 by Texas *
;* Instruments Incorporated. *
;* All rights reserved. *
;* *
;* Date Written: 2 May 1984 *
;* Last Modification: *
;* 11 Feb 86 - Replaced support for even? and odd? to reduce code size and *
;* to update error messages. *
;* - Improved error handling for divide,quotient, and remainder. *
;* - Fixed divide by zero error in Remainder function *
;* 21 Oct 86 - added an additional argument to %graphics - dbs *
;* 7 Nov 86 - %graphics accepts negative arguments (for clipping) - rb *
;* 7 Jan 87 - added random I/O - dbs *
;* 10 Feb 87 - added new opcode (186) for read-line - tc *
;* 8 Mar 87 - XLI - rb *
;* 16 Mar 87 - Added dos-err entry point for detection of Dos I/O errors. *
;* 17 Feb 88 - Mods so sinterp will work in protected mode - tc *
;* * Macros in SMMU.MAC allow stores into code segment *
;* * Graphics for pro mode moved to PROIO.ASM *
;* * %ESC function modified to look for sw-int and call *
;* SOFTINT function in PRO2REAL.ASM *
;* * Timer interrupts no longer taken over for pro mode. *
;* Engines work based on # vm instructions executed for pro *
;* mode. Interpreter loop for engines included (eng_next1) *
;* and settimer, rsttimer included here (conditionally of *
;* course). *
;* *
;* *
;******************************************************************************
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The following files are defined in smmu.equ but are split out here so
; that this module will assemble....
include schemed.equ
include schemed.ref
include schemed.mac
purge markedp,pushptr,popptr
include smmu.mac
purge %LoadPage,%LoadPage0,%LoadPage1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
include sinterp.mac
include sinterp.arg
include pcmake.equ
include stackf.equ ; define stack frame format
XGROUP group progx
progx segment word public 'progx'
IFDEF PROMEM
extrn softint:far ; interface for sw_int (see PRO2REAL.ASM)
ELSE
extrn graphit:far ; interface to graphics primitives
ENDIF
extrn str_apnd:far ; substring append support
extrn str_disp:far ; %substring-display support
progx ends
DGROUP group data
data segment word public 'DATA'
assume DS:DGROUP
extrn page0:word
; Primary opcode lookup table
op_table dw copy ; 000- load dest,src
dw ld_const ; 001- ld-const dest,constant-number (byte)
dw ld_imm ; 002- ld-imm dest,immed-value (byte)
dw ld_nil ; 003- ld-nil dest
dw PGROUP:ld_local ; 004- ld-local dest,entry-number (byte)
dw PGROUP:ld_lex ; 005- ld-lex dest,entry-no,delta-level
dw PGROUP:ld_env ; 006- ld-env R(dest),C(sym)
dw PGROUP:ld_globl ; 007- ld-global dest,constant-number (byte)
dw PGROUP:ld_fluid ; 008- ld-fluid dest,constant-number (byte)
dw ld_off_s ; 009- ld-vec-s vect,offset (byte)
dw ld_off_l ; 010- ld-vec-l vect,offset (word)
dw ld_off_r ; 011- ld-vec-r vect,offset (reg)
dw PGROUP:st_local ; 012- st-local src,entry-number (byte)
dw PGROUP:st_lex ; 013- st-lex src,entry-no,delta-level
dw PGROUP:st_env ; 014- st-env R(val),C(sym)
dw PGROUP:st_globl ; 015- st-global src,constant-number (byte)
dw PGROUP:st_fluid ; 016- st-fluid src,constant-number (byte)
dw st_off_s ; 017- st-vec-s vect,offset (byte),src
dw st_off_l ; 018- st-vec-l vect,offset (word),src
dw st_off_r ; 019- st-vec-r vect,offset (reg),src
dw PGROUP:set_car ; 020- set-car! dest,src
dw PGROUP:set_cdr ; 021- set-cdr! dest,src
dw recompil ; 022- (unused) formerly set-ref!
dw recompil ; 023- (unused) formerly swap-ref!
dw PGROUP:spop ; 024- pop dest
dw PGROUP:spush ; 025- push src
dw PGROUP:sdrop ; 026- drop count (unsigned byte)
dw PGROUP:ld_globr ; 027- ld-global-r dest,sym
dw recompil ; 028- (unused- formerly push-heap)
dw PGROUP:bind_fl ; 029- bind-fl const,src
dw PGROUP:unbind_f ; 030- unbind_fl count (byte)
dw PGROUP:define ; 031- define! src,const
dw jmp_shrt ; 032- jmp_s label (byte)
dw jmp_long ; 033- jmp_l label (word)
dw j_nil_s ; 034- jnil_s reg,label (byte)
dw j_nil_l ; 035- jnil_l reg,label (word)
dw j_nnil_s ; 036- jnnil_s reg,label (byte)
dw j_nnil_l ; 037- jnnil_l reg,label (word)
dw j_atm_s ; 038- jatom_s reg,label (byte)
dw j_atm_l ; 039- jatom_l reg,label (word)
dw j_natm_s ; 040- jnatom_s reg,label (byte)
dw j_natm_l ; 041- jnatom_l reg,label (word)
dw j_eq_s ; 042- jeq_s reg,label (byte)
dw j_eq_l ; 043- jeq_l reg,label (word)
dw j_neq_s ; 044- jneq_s reg,label (byte)
dw j_neq_l ; 045- jneq_l reg,label (word)
dw recompil ; 046- (unused) formerly deref
dw recompil ; 047- (unused) formerly ref
dw PGROUP:call_lcl ; 048- call lbl,delta-level,delta-heap
dw PGROUP:call_ltr ; 049- call-tr lbl,delta-level,delta-heap
dw PGROUP:call_cc ; 050- call/cc lbl,delta-level,delta-heap
dw PGROUP:cl_cctr ; 051- call/cc-tr lbl delta-level,delta-heap
dw PGROUP:call_clo ; 052- call-cl reg,number-args
dw PGROUP:call_ctr ; 053- call-cl-tr reg,number-args
dw PGROUP:clcc_c ; 054- call/cc-cl reg
dw PGROUP:clcc_ctr ; 055- call/cc-cl-tr reg
dw PGROUP:apply ; 056- apply-cl reg,arg
dw PGROUP:apply_tr ; 057- apply-cl-tr reg,arg
dw PGROUP:execute ; 058- execute reg
dw PGROUP:s_exit ; 059- exit
dw PGROUP:cr_close ; 060- close dest,label,number-args
dw PGROUP:drop_env ; 061- drop-env count
dw PGROUP:hash_env ; 062- make-hashed-environment
dw PGROUP:ld_fl_r ; 063- ld-fluid-r dest,sym
dw PGROUP:ld_car ; 064- car dest,src
dw PGROUP:ld_cdr ; 065- cdr dest,src
dw PGROUP:ld_caar ; 066- caar dest,src
dw PGROUP:ld_cadr ; 067- cadr dest,src
dw PGROUP:ld_cdar ; 068- cdar dest,src
dw PGROUP:ld_cddr ; 069- cddr dest,src
dw PGROUP:ld_caaar ; 070- caaar dest,src
dw PGROUP:ld_caadr ; 071- caadr dest,src
dw PGROUP:ld_cadar ; 072- cadar dest,src
dw PGROUP:ld_caddr ; 073- caddr dest,src
dw PGROUP:ld_cdaar ; 074- cdaar dest,src
dw PGROUP:ld_cdadr ; 075- cdadr dest,src
dw PGROUP:ld_cddar ; 076- cddar dest,src
dw PGROUP:ld_cdddr ; 077- cdddr dest,src
dw PGROUP:ld_caddd ; 078- cadddr dest,src
dw PGROUP:s_cons ; 079- cons dest,car,cdr
dw add ; 080- add dest,src
dw addi ; 081- add-imm dest,imm (signed byte)
dw sub ; 082- sub dest,src
dw mul ; 083- mul dest,src
dw muli ; 084- mul-imm dest,imm (signed byte)
dw div ; 085- div dest,src
dw divi ; 086- div-imm dest,imm (signed byte)
dw quo ; 087- quotient dest,src **integers only**
dw modulo ; 088- remainder dest,src
dw PGROUP:ld_car1 ; 089- %car src=dest
dw PGROUP:ld_cdr1 ; 090- %cdr src=dest
dw random ; 091- %random dest
dw lt_p ; 092- < dest,src
dw le_p ; 093- <= dest,src
dw eq_n ; 094- = dest,src
dw gt_p ; 095- > dest,src
dw ge_p ; 096- >= dest,src
dw ne_p ; 097- <> dest,src
dw maximum ; 098- max dest,src
dw minimum ; 099- min dest,src
dw eq_p ; 100- eq? dest,src
dw eqv_p ; 101- eqv? dest,src
dw equal_p ; 102- equal? dest,src
dw PGROUP:memq ; 103- memq dest,src
dw PGROUP:memv ; 104- memv dest,src
dw PGROUP:member ; 105- member dest,src
dw reverseb ; 106- reverse! list
dw not_yet ; 107- reverse list
dw PGROUP:assq ; 108- assq obj,list
dw PGROUP:assv ; 109- assv obj,list
dw PGROUP:assoc ; 110- assoc obj,list
dw PGROUP:s_list ; 111- list obj
dw PGROUP:appendb ; 112- append! list,obj
dw append ; 113- append list,obj
dw not_yet ; 114- delq! obj,list
dw not_yet ; 115- delete! obj,list
dw getprop ; 116- get-prop name,prop
dw putprop ; 117- put-prop name,val,prop
dw proplist ; 118- proplist name
dw remprop ; 119- remprop name,prop
dw PGROUP:list2 ; 120- list2 dest=src1,src2
dw not_yet ; 121- list-ref dest=src1,src2
dw PGROUP:l_tail ; 122- list-tail dest,count
dw not_op ; 123- (unused)
dw not_op ; 124- (unused)
dw b_xor ; 125- bitwise-xor dest=src1,src2
dw b_and ; 126- bitwise-and dest=src1,src2
dw b_or ; 127- bitwise-or dest=src1,src2
; Note: the second half of the opcodes are "second class" opcodes,
; in that TIPC register BH will not be zero at the entry to the
; support routine. For the following instructions, BH will
; contain the value one (1).
dw atom_p ; 128- atom? dest
dw closur_p ; 129- closure? dest
dw code_p ; 130- code? dest
dw contin_p ; 131- continuation? dest
dw even_p ; 132- even? dest
dw float_p ; 133- float? dest
dw PGROUP:fluid_p ; 134- fluid-bound? dest
dw integr_p ; 135- integer? dest
dw null_p ; 136- null? dest
dw number_p ; 137- number? dest
dw odd_p ; 138- odd? dest
dw pair_p ; 139- pair? dest
dw port_p ; 140- port? dest
dw proc_p ; 141- proc? dest
dw recompil ; 142- (unused) formerly ref?
dw string_p ; 143- string? dest
dw symbol_p ; 144- symbol? dest
dw vector_p ; 145- vector? dest
dw eq_z_p ; 146- zero? dest
dw lt_z_p ; 147- negative? dest
dw gt_z_p ; 148- positive? dest
dw sabs ; 149- abs dest
dw float ; 150- float dest
dw minus ; 151- minus dest
dw sfloor ; 152- floor dest
dw sceiling ; 153- ceiling dest
dw struncat ; 154- truncate dest
dw sround ; 155- round dest
dw char_p ; 156- char? dest
dw PGROUP:env_p ; 157- env? dest
dw not_op ; 158- (unused)
dw not_op ; 159- (unused)
dw asc_char ; 160- asc->char reg
dw char_asc ; 161- char->asc reg
dw recompil ; 162- (unused) formerly gensym
dw not_op ; 163- (unused)
dw not_op ; 164- (unused)
dw slength ; 165- length list
dw lst_pair ; 166- last-pair list
dw substr ; 167- substr str,pos,len
dw PGROUP:vec_allo ; 168- alloc-vec dest
dw PGROUP:vec_size ; 169- vect-length dest
dw PGROUP:vec_fill ; 170- vect-fill vect,val
dw not_yet ; 171- make-pack-vect len,bits/elem,signed?
dw s_disply ; 172- %substr-display str,start,end,row,wind
dw not_op ; 173- (unused)
dw set_tim ; 174- %start-timer src=ticks
dw rst_tim ; 175- %stop-timer dest=ticks remaining
dw popen ; 176- open-port filename,mode
dw pclose ; 177- close-port port
dw PGROUP:spprin1 ; 178- prin1 obj,port
dw PGROUP:spprinc ; 179- princ obj,port
dw PGROUP:spprint ; 180- print obj,port
dw PGROUP:spnewlin ; 181- newline port
dw recompil ; 182- (unused) formerly read
dw recompil ; 183- (unused) formerly file-exists?
dw PGROUP:prt_len ; 184- print-length obj
dw recompil ; 185- (unused) formerly current-column
dw PGROUP:srd_line ; 186- read-line dest=src (src={port})
dw PGROUP:srd_atom ; 187- read-atom dest=src (src={port})
dw PGROUP:read_cha ; 188- read-char dest=src
dw PGROUP:trns_chg ; 189- %transcript src
dw PGROUP:rd_ch_rd ; 190- read-char-ready? dest=src
dw sfasl ; 191- fasl string
dw PGROUP:ch_eq_p ; 192- char= char1,char2
dw PGROUP:ch_eq_ci ; 193- char-equal? char1,char2
dw PGROUP:ch_lt_p ; 194- char< char1,char2
dw PGROUP:ch_lt_ci ; 195- char-less? char1,char2
dw PGROUP:ch_up ; 196- char-upcase char
dw PGROUP:ch_down ; 197- char-downcase char
dw str_lng ; 198- string-length string
dw PGROUP:st_ref ; 199- string-ref string,index
dw PGROUP:st_set ; 200- string-set! string,index,char
dw PGROUP:make_str ; 201- make-string length,char
dw PGROUP:str_fill ; 202- string-fill! string,char
dw str2sym ; 203- string->symbol string
dw str2usym ; 204- string->uninterned-symbol string
dw sym2str ; 205- symbol->string symbol
dw srch_nx ; 206- srch-next str,start,end,charset
dw srch_pr ; 207- srch-prev str,start,end,charset
dw PGROUP:make_win ; 208- make-window label
dw set_w_at ; 209- set-wind-attr wind,attr,value
dw PGROUP:get_wind ; 210- get-wind-attr wind,attr
dw clr_wind ; 211- clear-window wind
dw PGROUP:save_win ; 212- save-window wind
dw PGROUP:rest_win ; 213- restore-wind wind
dw s_append ; 214- %str-append R(d=s1),R(s2),...,R(s7)
dw PGROUP:sgraph ; 215- %graphics R(s1),R(s2),...,R(s7)
dw sreify ; 216- %reify R(s1=d),R(s2) ;obj,indx
dw PGROUP:mk_env ; 217- mk-env R(d)
dw PGROUP:env_par ; 218- env-par R(d=s1) ; s1=env
dw PGROUP:env_lu ; 219- env-lu R(d=s1),R(s2) ; sym,env
dw PGROUP:def_env ; 220- def-env R(d=s1),R(s2),R(s3) sve
dw PGROUP:push_env ; 221- push-env C(s1) ; s1=list of syms
dw PGROUP:drop_env ; 222- drop-env
dw PGROUP:ld_env ; 223- ld-env R(d),C(s1) ; s1=symbol
dw PGROUP:st_env ; 224- st-env R(d=s1),C(s2) ; val,sym
dw PGROUP:set_gnv ; 225- set-glob-env! R(s1) ; s1=env
dw sreifyb ; 226- %reify! R(s1),R(s2),R(s3);o,i,v
dw obj_hash ; 227- object-hash R(d=s1)
dw obj_unhs ; 228- object-unhash R(d=s1)
dw reify_s ; 229- reify-stack R(d=s1)
dw reify_sb ; 220- reify-stack! R(s1),R(s2)
dw sfpos ; 231- set-file-position!
dw s_esc1 ; 232- %esc1 R(d=s1)
dw s_esc2 ; 233- %esc2 R(d=s1),R(s2)
dw s_esc3 ; 234- %esc3 R(d=s1),R(s2),R(s3)
dw s_esc4 ; 235- %esc4 R(d=s1),R(s2),...,R(s4)
dw s_esc5 ; 236- %esc5 R(d=s1),R(s2),...,R(s5)
dw s_esc6 ; 237- %esc6 R(d=s1),R(s2),...,R(s6)
dw s_esc7 ; 238- %esc7 R(d=s1),R(s2),...,R(s7)
dw xesc ; 239- %xesc R(d=s1),R(len),
; R(arg1),...,R(arg16);
; all R(argn) are optional
dw not_op ; 240- (unused)
dw not_op ; 241- (unused)
dw not_op ; 242- (unused)
dw not_op ; 243- (unused)
dw not_op ; 244- (unused)
dw not_op ; 245- (unused)
dw not_op ; 246- (unused)
dw sgc2 ; 247- gc-with-compaction
dw exit_op ; 248- halt=(exit) [return to MS-DOS]
dw gc ; 249- %garbage-collect
dw ptyme ; 250- %internal-time dest
dw reset ; 251- reset
dw s_reset ; 252- scheme-reset
dw clr_regs ; 253- %clear-registers
dw not_op ; 254- (reserved for escape)
dw debug_op ; 255- %begin-debug
reset_BP dw 0 ; initial value of BP for reset purposes
zero_reg dw 0,SPECFIX*2 ; a "register" containing a fixnum 0
zero_adr dw zero_reg ; the address of "zero_reg" (for pushing)
m_one dw 1 ; a constant "one" (1)
m_zerodv dw ZERO_DIVIDE_ERROR ; error code for division by zero
m_not_op db "[VM INTERNAL ERROR] Undefined opcode",LF,0
m_cod_er db "[VM INTERNAL ERROR] %x:%04x isn't a code base",LF,0
m_not_yt db "[VM INTERNAL ERROR] Feature not implemented",LF,0
m_recomp db "[VM ERROR encountered!] Object module incompatible with "
db "this Version",LF,"Recompile from Source",LF,0
;;;m_il_st db "[VM ERROR encountered!] VECTOR-SET! operand is write "
;;; db "protected",LF,0
;;;m_deref db "DEREF",0
m_ld_r db "LD_R",0
m_st_r db "ST_R",0
;;;m_setref db "SET_REF!",0
;;;m_swaprf db "SWAP_REF!",0
m_revb db "REVERSE!",0
m_even db "EVEN?",0
m_odd db "ODD?",0
m_v_ld db "VECTOR-REF",0
m_v_st db "VECTOR-SET!",0
m_DIV db "/",0
m_MODULO db "REMAINDER",0
m_QUOTNT db "QUOTIENT",0
m_VOE dw VECTOR_OFFSET_ERROR ; error number for "offset out of range"
masc_ch db "INTEGER->CHAR",0
mch_asc db "CHAR->INTEGER",0
m_bckwrd db "[VM INTERNAL ERROR] sinterp: instruction preceding %x:%04x "
db "set direction flag",LF,0
m_reg0 db "[VM INTERNAL ERROR] sinterp: instruction preceding %x:%04x "
db "clobbered register",LF,0
;;;m_bad_st db "[VM INTERNAL ERROR] sinterp: instruction preceding %x:%04x "
;;; db "screwed up the stack",LF,0
IFNDEF PROMEM
m_graph db "%GRAPHICS",0
ENDIF
m_esc db "%ESCN",0
; XLI errors (numbered from 1, not 0)
xli_err dw 0 ;this spot unused
dw 0,xli_err2 ;other 0's no longer used spots
dw 0,xli_err4,xli_err5,xli_err6
dw xli_err7,xli_err8,xli_err9,xli_err10,xli_err11,xli_err12
dw xli_err13,xli_err14,xli_err15,xli_err16
; XLI fatal errors print via print_and_exit
;xli_err1 db '[VM FATAL ERROR] Unable to determine length of %XESC VM instruction',LF,0
; XLI normal errors print via sch_err as secondary line to [VM ERROR ...] message
xli_err2 db '[XLI] First argument to XCALL is not string or symbol',0
;xli_err3 db '[XLI] Improper number of arguments given to XCALL',0
xli_err4 db '[XLI] An argument to XCALL is invalid',0
xli_err5 db '[XLI] The return value of XCALL is invalid',0
xli_err6 db '[XLI] The function requested by XCALL is not available',0
xli_err7 db '[XLI] Number too large to fit in 32 bits',0
xli_err8 db '[XLI] Sync error',0
xli_err9 db '[XLI] Error in releasing memory of external program',0
xli_err10 db '[XLI] No memory is available for external program',0
xli_err11 db '[XLI] Error in loading external program',0
xli_err12 db '[XLI] No more external programs can be loaded',0
xli_err13 db '[XLI] File to load not found',0
xli_err14 db '[XLI] Number too large to fit in 16 bits',0
xli_err15 db '[XLI] Version mismatch',0
xli_err16 db '[XLI] Error reported by external program',0
IFDEF PROMEM
;
; Following definitions are for protected mode engines. They will be
; used in eng_next1, settimer, and rsttimer defined later in this
; module.
;
tickstat db -1 ;status of engine (0=timeout,1=running,-1=none)
lo_time dw ? ;timer ticks (per vm instuction executed)
hi_time dw ?
ENDIF
data ends
PGROUP group prog
prog segment byte public 'PROG'
assume CS:PGROUP
; Interpreter support routines defined in "scar_cdr.asm"
extrn ld_car:near
extrn ld_cdr:near
extrn ld_car1:near
extrn ld_cdr1:near
extrn ld_caar:near
extrn ld_cadr:near
extrn ld_cdar:near
extrn ld_cddr:near
extrn ld_caaar:near
extrn ld_caadr:near
extrn ld_cadar:near
extrn ld_caddr:near
extrn ld_cdaar:near
extrn ld_cdadr:near
extrn ld_cddar:near
extrn ld_cdddr:near
extrn ld_caddd:near
extrn set_car:near
extrn set_cdr:near
extrn s_cons:near
extrn s_list:near ; (list obj)
extrn list2:near ; (list a b)
extrn appendb:near ; (append! a b)
extrn l_tail:near ; (list-tail list count)
; Interpreter support routines defined in "sstack.asm"
extrn set_pos:far ; set-file-position!
; Interpreter support routines defined in "sstack.asm"
extrn spush:near ; push register contents onto Scheme stack
extrn spop:near ; pop into register from Scheme stack
extrn sdrop:near ; drop elements from top of Scheme stack
extrn ld_local:near ; load from local stack frame
extrn st_local:near ; store into local stack frame
extrn ld_lex:near ; load from higher level stack frame
extrn st_lex:near ; store into higher level stack frame
extrn call_lcl:near ; local call
extrn call_ltr:near ; local call, tail recursive
extrn call_clo:near ; call closure object
extrn call_ctr:near ; call closure object, tail recursive
extrn call_cc:near ; local call/cc
extrn cl_cctr:near ; local call/cc, tail recursive
extrn clcc_c:near ; call/cc, closure object
extrn clcc_ctr:near ; call/cc, closure object, tail recursive
extrn apply:near ; apply closure object
extrn apply_tr:near ; apply closure object, tail recursive
extrn execute:near ; execute code block
extrn s_exit:near ; exit procedure
extrn cr_close:near ; create closure
extrn force_ca:near ; entry point to force call (to debugger)
; Interpreter support routines defined in "svars.asm"
extrn ld_fluid:near ; load value of fluid variable
extrn ld_fl_r:near ; load value of fluid variable - reg source
extrn st_fluid:near ; store value into fluid variable
extrn bind_fl:near ; bind fluid variable
extrn unbind_f:near ; unbind fluid variables
extrn fluid_p:near ; fluid-bound? predicate
extrn vec_allo:near ; allocate vector
extrn vec_size:near ; vector-size
extrn vec_fill:near ; vector-fill
extrn memq:near ; memq
extrn memv:near ; memv
extrn member:near ; member
extrn assq:near ; assq
extrn assv:near ; assv
extrn assoc:near ; assoc
; Interpreter support routines defined in "sstring.asm"
extrn ch_eq_p:near ; (char= char1 char2)
extrn ch_eq_ci:near ; (char-equal? char1 char2)
extrn ch_lt_p:near ; (char< char1 char2)
extrn ch_lt_ci:near ; (char-less? char1 char2)
extrn ch_up:near ; (char-upcase char)
extrn ch_down:near ; (char-downcase char)
extrn make_str:near ; (make-string len char)
extrn str_fill:near ; (string-fill! string char)
extrn st_ref:near ; (string-ref string index)
extrn st_set:near ; (string-set! string index char)
; Interpreter support routines defined in "senv.asm"
extrn env_p:near ; (environment? obj)
extrn mk_env:near ; (make-environment)
extrn env_par:near ; (environment-parent env)
extrn env_lu:near ; (environment-lookup sym env)
extrn def_env:near ; (define symbol value env)
extrn push_env:near ; (push-environment list)
extrn drop_env:near ; (drop-environment)
extrn hash_env:near ; (make-hashed-environment)
extrn ld_env:near ; (load-env symbol)
extrn st_env:near ; (store-env value symbol)
extrn set_gnv:near ; (set-global-env! env)
extrn ld_globl:near ; load value of global variable
extrn ld_globr:near ; load value of global variable - reg source
extrn st_globl:near ; store value into global variable
extrn define:near ; define! value for global variable
; Interpreter support routines defined in "sobjhash.asm"
extrn obj_hash:near ; (object-hash obj)
extrn obj_unhs:near ; (object-unhash obj)
; Interpreter support routines defined in "cwindow.asm"
extrn make_win:near ; (make-window label)
extrn get_wind:near ; (get-window-attribute port attribute)
extrn save_win:near ; (window-save-contents port)
extrn rest_win:near ; (window-restore-contents port contents)
extrn trns_chg:near ; (transcript-on "filename")
extrn rd_ch_rd:near ; (read-char-ready? port)
extrn read_cha:near ; (read-char port)
; Interpreter support routines defined in "cread.asm"
extrn srd_line:near ; (read-line port)
extrn srd_atom:near ; (read-atom port)
; Interpreter support routines defined in "cprint.asm"
extrn spprin1:near
extrn spprinc:near
extrn spprint:near
extrn spnewlin:near
extrn prt_len:near
; XLI
extrn xli_xesc:near ; XLI xesc handler
; extrn print_an:near ; fatal errors
IFDEF PROMEM
; GRAPHICS - protected mode scheme graphics handler in PROIO.ASM
extrn sgraph:near ;Handle %graphics primitives
ENDIF
; Entry point to force debug mode prior to next VM instruction
public force_de
force_de: mov AX,word ptr CS:trc_forc
STORE_WORD_IN_CS PROG,next1,AX ; Protected Mode Macro
ret
IFNDEF PROMEM
; Entry point to force a timeout prior to next VM instruction. This
; will be called from the tick routine in STIMER.ASM. Protected
; mode scheme doesn't use this, as it counts vm instructions as
; engine ticks.
;
public force_ti
force_ti: mov AX,word ptr CS:tim_forc
XCHG_WORD_IN_CS PROG,next1,AX ;Protected Mode Macro
STORE_WORD_IN_CS PROG,reset_tim,AX ;Protected Mode Macro
ret
ENDIF
; Entry point to process shift-break prior to next VM instruction
public shft_brk
dbg_addr dw VM_debug ; address of the variable VM_debug
dw DGROUP ; DGROUP segment address
sbrk_adr dw s_break ; address of the variable s_break
reset_sb dw 0
shft_brk: push ES ; save the current ES
les SI,dword ptr CS:dbg_addr ; load the long address for VM_debug
mov DI,CS:sbrk_adr ; load address for s_break
inc word ptr ES:[DI] ; and increment shift-break flag
cmp word ptr ES:[SI],0 ; are we in VM_debug mode?
pop ES ; restore ES
jne force_de ; if we're in VM_debug mode, jump
mov AX,word ptr CS:shft_nxt ; else, force a trap to the debugger
cmp AX,word ptr CS:next1 ; Shift-Brk already depressed?
je shft_brt ; if a duplicate request, skip it
XCHG_WORD_IN_CS PROG,next1,AX ; else enter scheme debugger on
STORE_WORD_IN_CS PROG,reset_sb,AX ; next vm instruction
shft_brt: ret ; continue processing
public run,interp
run proc near
mov AX,word ptr CS:next_go1 ; modify interpreter loop to disable
STORE_WORD_IN_CS PROG,next1,AX ; instruction level trace capability
interp: push BP
sub SP,offset sint_BP
mov BP,SP
mov reset_BP,BP ; save initial value of BP for reset
; Set up initial interpreter parameters
mov [BP].C_ES,ES
mov SI,[BP].cod_ent ; load address of entry point offset
mov SI,[SI] ; and load PC
mov BX,CB_pag ; load code base page number
cmp ptype+[BX],CODETYPE*2 ; if page doesn't contain code,
jne code_err ; we've got an error
LoadCode ES,BX ; load code page paragraph addr
; mov ES,pagetabl+[BX] ; load code page paragraph addr
mov [BP].save_ES,ES ; and save it off
jmp next ; jump to start of interpreter
; ***error-- invalid code base-- not a code page***
code_err: ; push the ptr's disp, page no, and
mov AX,offset DGROUP:m_cod_er ; address of message
pushm <CB_dis,BX,AX>
C_call printf ; print error message
jmp debug ; begin debug mode
trc_oops: cld ; clear direction * checking code
lea BX,m_bckwrd ; * (see below)
jmp short trc_err ; *
trc_reg0: lea BX,m_reg0
trc_err: mov AX,CB_pag ; R0 not nil-- print error message
corrpage AX
pushm <SI,AX,BX>
C_call printf,<SI>,Load_ES
restore <SI>
jmp debug
;**bad_stk:
;** lea BX,m_bad_st ; inconsistent runtime stack error
;** jmp short trc_err
next_tr1:
dec [BP].no_insts ; decrement count of instructions to run
jge next_go ; if not zero, continue decoding
jmp exit ; out of instructions-- return to debugger
next_go1 equ $
next_go: xor AX,AX ; Clear high order byte of AX
mov BX,SI ;* These instructions check to make
xor SI,SI ; * sure that the direction flag is set
lodsb ; * in the forward direction. If not,
cmp SI,1 ; * the "lods" in the interpreter will
mov SI,BX ; * decrement the location pointer
jne trc_oops ;* instead of incrementing it.
cmp reg0_pag,NIL_PAGE*2 ;*
jne trc_reg0 ; * These instructions check to
cmp reg0_dis,NIL_DISP ; * make sure R0 contains nil (by
jne trc_reg0 ;* convention)
cmp page0,0 ;*
jne trc_reg0 ; *
cmp page0+2,0 ; * Verify that the location for
jne trc_reg0 ; * the null pointer (page 0, offset 0)
cmp page0+4,0 ; * is still (cons '() '())
jne trc_reg0 ;*
; Validate the contents of each of the Scheme registers
mov CX,NUM_REGS+4 ; load number of regsiter into CX (counter)
; Note: also checks GNV_reg, FNV_reg, CB_reg, and tmp_reg
mov DI,offset reg0 ; address of register 0
mov DX,nextpage ; load number of pages allocated
more_reg: mov AX,[DI].C_page ; load page number field of next register
cmp AX,SPECFIX*2 ; does register contain a fixnum?
je off_ok ; if so, skip offset check (jump)
cmp AX,SPECCHAR*2 ; does register contain a character?
je off_ok ; if so, skip offset check (jump)
mov BX,AX ; copy page number (times 2) into BX
ror AX,1 ; divide by 2, LSB to sign position
cmp AX,DX ; is page number too large?
jae trc_reg0 ; if too large or odd, error (jump)
mov AX,[DI].C_disp ; load displacement field from register
cmp AX,psize+[BX] ; is offset too big?
jae trc_reg0 ; if offset too big, error (jump)
off_ok: add DI,size C_ptr ; increment register offset
loop more_reg ; continue testing all registers
;** Test consistency of Scheme's runtime stack
;** mov BX,FP ; load current stack frame pointer
;** cmp BX,0
;** je stk_ok
;**more_stk:
;** mov AL,S_stack+[BX] ; load return address code base page number
;** mov DI,AX
;** cmp byte ptr ptype+[DI],CODETYPE*2 ; is this a code block?
;** jne bad_stk ; if not, bad dynamic link
;** cmp byte ptr S_stack+[BX]+6,SPECFIX*2 ; is dynamic link a fixnum?
;** jne bad_stk ; if not, bad dynamic link
;** mov BX,word ptr S_stack+[BX]+7 ; load pointer to caller's FP
;** sub BX,BASE ; inside current stack buffer?
;** ja more_stk ; if so, continue testing (jump)
;**stk_ok:
xor AX,AX ; clear TIPC register AX
lods byte ptr ES:[SI] ; Fetch next instruction's opcode
mov BX,AX
shl BX,1 ; Multiply opcode by two for use as index
jmp op_table+[BX]
trc_go equ $
jmp short $+(next_trc-next1) ; jump to overwrite "next" for debug
next_trc: jmp next_tr1
tim_forc equ $
jmp short $+(next_tim-next1) ; jump to force debug mode
next_tim: jmp timeout ; Force execution into debug mode
trc_forc equ $
jmp short $+(next_dbg-next1) ; jump to force debug mode
next_dbg: jmp debug ; Force execution into debug mode
shft_nxt equ $
jmp short $+(next_sb-next1) ; jump to force Scheme debug mode
next_sb : jmp sc_debug ; Force execution into Scheme debug mode
IFDEF PROMEM
;
; The following code is for use by engines under protected mode scheme.
; We had a problem collecting timer interrupts from AI Architects OSx86,
; so I just implemented a different interpreter loop which decrements
; a timer tick upon each vm instruction.
;
; Note: this code must be within 128 bytes of next1 (below) so that a
; short jump can be performed.
eng_tick equ $
jmp short $+(eng_next1-next1) ; jump to engine loop
eng_next1:
sub lo_time,1 ;decrement engine tick
sbb hi_time,0 ;if not zero
jnz eng_next2 ; continue
cmp lo_time,0
jnz eng_next2
mov tickstat,0 ;zero counter, record timeout
jmp timeout ;force timeout condition
eng_next2:
xor ax,ax ;clear high order byte of ax
lods byte ptr es:[si] ;fetch next instruction's opcode
mov bx,ax
shl bx,1 ;make into index
jmp op_table+[bx] ;go execute the vm instruction code
ENDIF
;
; Following is the main vm interpreter loop. Note that the location at
; next1 can (and will be) code modified to jump into the debugger, a
; trace loop, and a loop for handling engines in protected mode.
;
public next_SP,next_PC,next
next_SP: mov SP,BP ; Restore SP after call
next_PC: les SI,dword ptr [BP].save_SI ; Reload interpreter's PC & ES
next:
next1 equ $
xor AX,AX ; Clear high order byte of AX
lods byte ptr ES:[SI] ; Fetch next instruction's opcode
mov BX,AX
shl BX,1 ; Multiply opcode by two for use as index
jmp op_table+[BX] ; go execute the vm instruction code
; Jump if nil, short JNILS reg,offset
j_nil_s: lods word ptr ES:[SI] ; load operand, offset
mov BL,AL ; copy register number
cmp byte ptr reg0_pag+[BX],0 ; test for null pointer
jne next ; Jump if not nil
mov AL,AH
cbw ; Sign extend short displacement
add SI,AX ; Add jump offset to current PC
jmp next ; Return to interpreter
; Jump if not nil, short JNNILS reg,offset
j_nnil_s: lods word ptr ES:[SI] ; load operand, offset
mov BL,AL ; copy register number
cmp byte ptr reg0_pag+[BX],0 ; test for null pointer
je next ; Jump if nil
mov AL,AH
cbw ; Sign extend short displacement
add SI,AX ; Add jump offset to current PC
jmp next ; Return to interpreter
; Jump if atom,short JATOMS reg,offset
j_atm_s: lods word ptr ES:[SI] ; Load register, offset
mov BL,AL ; copy register number to test
test attrib+[BX],ATOM ; test for atom attribute
jz next ; if not atom, return to interpreter
mov AL,AH ; position branch offset and
cbw ; sign extend to 16 bits
add SI,AX ; add jump offset to current PC
jmp next ; return to interpreter
; Jump if not atom,short JNATOMS reg,offset
j_natm_s: lods word ptr ES:[SI] ; Load register, offset
mov BL,AL ; copy register number to test
test attrib+[BX],ATOM ; test for atom attribute
jnz next ; if atom, return to interpreter
mov AL,AH ; position branch offset and
cbw ; sign extend to 16 bits
add SI,AX ; add jump offset to current PC
jmp next ; return to interpreter
; Jump if eq?, short JEQS src1,src2,offset
j_eq_s: lods word ptr ES:[SI] ; load registers to compare
mov BL,AH
mov DI,BX
add DI,offset reg0 ; compute address of src2
mov BL,AL ; copy src1 register number
lods byte ptr ES:[SI] ; load branch displacement,
cbw ; sign extend,
mov CX,AX ; and save it
mov AX,reg0_dis+[BX]
cmp AX,[DI].C_disp ; are displacements eq?
jne next
j_eq_s1: mov AL,byte ptr reg0_pag+[BX]
cmp AL,byte ptr [DI].C_page ; are page numbers eq?
jne j_eq_nxt
add SI,CX ; add offset to current PC
j_eq_nxt: jmp next
; Jump if not eq?, short JNEQS src1,src2,offset
j_neq_s: lods word ptr ES:[SI] ; load registers to compare
mov BL,AH
mov DI,BX
add DI,offset reg0 ; compute address of src2
mov BL,AL ; copy src1 register number
lods byte ptr ES:[SI] ; load branch displacement,
cbw ; sign extend,
mov CX,AX ; and save it
mov AX,reg0_dis+[BX]
cmp AX,[DI].C_disp ; are displacements eq?
jne j_neq_s2
j_neq_s1: mov AL,byte ptr reg0_pag+[BX]
cmp AL,byte ptr [DI].C_page ; are page numbers eq?
je j_neq_s3
j_neq_s2: add SI,CX ; add offset to current PC
j_neq_s3: jmp next
; Jump if eq?, long JEQL src1,src2,offset
j_eq_l: lods word ptr ES:[SI] ; load registers to compare
mov BL,AH
mov DI,BX
add DI,offset reg0 ; compute address of src2
mov BL,AL ; copy src1 register number
lods word ptr ES:[SI] ; load branch displacement
mov CX,AX ; and save same
mov AX,reg0_dis+[BX]
cmp AX,[DI].C_disp ; are displacements eq?
je j_eq_s1 ; if eq?, continue testing
jmp next ; otherwise, back to interpreter
; Jump if not eq?, long JNEQL src1,src2,offset
j_neq_l: lods word ptr ES:[SI] ; load registers to compare
mov BL,AH
mov DI,BX
add DI,offset reg0 ; compute address of src2
mov BL,AL ; copy src1 register number
lods word ptr ES:[SI] ; load branch displacement
mov CX,AX ; and save same
mov AX,reg0_dis+[BX]
cmp AX,[DI].C_disp ; are displacements eq?
je j_neq_s1 ; if equal, continue test
add SI,CX ; add offset to current location pointer
jmp next ; back to the interpreter
; Jump if nil, long JNILL reg,offset
j_nil_l: lods byte ptr ES:[SI] ; Load the register to test
mov BL,AL ; copy register number
lods word ptr ES:[SI] ; load branch offset
cmp byte ptr reg0_pag+[BX],0 ; Test for null pointer
jne j_nil_l1 ; Jump if not nil
add SI,AX ; Add jump offset to current PC
j_nil_l1: jmp next ; Return to interpreter
; Jump if not nil, long JNNILL reg,offset
j_nnil_l: lods byte ptr ES:[SI] ; Load the register to test
mov BL,AL ; copy register number
lods word ptr ES:[SI] ; load branch offset
cmp byte ptr reg0_pag+[BX],0 ; Test for null pointer
je j_nnil_1 ; if nil, return to interpreter
add SI,AX ; Add jump offset to current PC
j_nnil_1: jmp next ; Return to interpreter
; Jump if atom,long JATOMS reg,offset
j_atm_l: lods byte ptr ES:[SI] ; Load register to test
mov BL,AL ; copy register number to test
lods word ptr ES:[SI] ; load branch offset
test attrib+[BX],ATOM ; test for atom attribute
jz j_atm_l1 ; if not atom, return to interpreter
add SI,AX ; add jump offset to current PC
j_atm_l1: jmp next ; return to interpreter
; Jump if not atom,long JNATOMS reg,offset
j_natm_l: lods byte ptr ES:[SI] ; Load register to test
mov BL,AL ; copy register number to test
lods word ptr ES:[SI] ; load branch offset
test attrib+[BX],ATOM ; test for atom attribute
jnz j_natm_1 ; if atom, return to interpreter
add SI,AX ; add jump offset to current PC
j_natm_1: jmp next ; return to interpreter
; Jump unconditionally, short
jmp_shrt: lods byte ptr ES:[SI]
cbw ; sign extend the byte offset
add SI,AX
jmp next
; Jump unconditionally, long
jmp_long: lods word ptr ES:[SI]
add SI,AX
jmp next
; Move register to register: COPY dest,src
copy: lods word ptr ES:[SI] ; load regs, increment PC
mov BL,AH ; copy source register number into
mov DI,BX ; DI (clear high byte)
mov BL,AL ; copy destination register number
mov AX,reg0_dis+[DI]
mov reg0_dis+[BX],AX
mov AL,byte ptr reg0_pag+[DI]
mov byte ptr reg0_pag+[BX],AL
jmp next
;************************************************************************
;* AL AH *
;* Load constant from constant's area LD-CONST dest,const *
;* *
;* Purpose: Interpreter support for loading a compile time constant *
;* into a register of the Scheme virtual machine. *
;************************************************************************
ld_const: lods word ptr ES:[SI] ; load dest reg and constant number
mov BL,AL ; copy destination register number
mov DI,BX ; into TIPC register DI
mov BL,AH ; isolate constant number
mov AX,BX ; BX <- constant number * 3
shl AX,1
add BX,AX
add BX,CB_dis ; add displacement to start of code block
mov AL,ES:[BX].cod_cpag
mov byte ptr reg0_pag+[DI],AL
mov AX,ES:[BX].cod_cdis
mov reg0_dis+[DI],AX
jmp next
;************************************************************************
;* AL AH *
;* Load immediate value LD-IMM dest,imm *
;* *
;* Purpose: Interpreter support for loading an immediate value *
;* into a register of the Scheme virtual machine. *
;************************************************************************
ld_imm: lods word ptr ES:[SI] ; load dest reg, immediate value
mov BL,AL ; copy the destination register number
mov AL,AH ; isolate and sign extend the
cbw ; immediate value
sal AX,1 ; clear high order byte of immediate
shr AX,1 ; value, and
mov reg0_dis+[BX],AX ; store it
mov byte ptr reg0_pag+[BX],SPECFIX*2 ; set reg tag=fixnum
jmp next
;************************************************************************
;* Load nil ld-nil dest *
;* *
;* Purpose: Scheme interpreter support to load the value "nil" into *
;* a VM register *
;************************************************************************
ld_nil: lods byte ptr ES:[SI] ; load destination register number
mov BX,AX
xor AX,AX
mov byte ptr reg0_pag+[BX],AL ; store value of 'nil into
mov reg0_dis+[BX],AX ; destination register
jmp next ; back to the interpreter
;************************************************************************
;* Macro Support for Vector Load *
;************************************************************************
vec_load macro ld_type
local y,z
IFIDN <ld_type>,<LONG>
mov DX,4 ; record length of this instruction
lods byte ptr ES:[SI] ; load vector pointer/destination reg
mov DI,AX ; copy pointer to TIPC register DI
lods word ptr ES:[SI] ; load fullword offset
jmp short ld_v_go1 ; continue processing
ELSE
lods word ptr ES:[SI] ; load vect pointer, offset operands
mov BL,AL ; copy vector pointer/destination reg
mov DI,BX ; number into TIPC register DI
IFIDN <ld_type>,<SHORT>
mov AL,AH ; convert immediate byte offset to
cbw ; a fullword value
jmp short ld_v_go ; continue processing
ELSE
IFIDN <ld_type>,<REG>
mov BL,AH ; copy number of index register
cmp byte ptr reg0_pag+[BX],SPECFIX*2 ; index a fixnum?
jne z ; if not, error (jump)
mov AX,reg0_dis+[BX] ; load immediate value from index register
shl AX,1 ; sign extend 15 bit immediate
sar AX,1
ld_v_go: mov DX,3 ; record length of this instruction
ld_v_go1: save <SI> ; save current location pointer
mov CX,AX ; multiply the index value by 3
shl AX,1 ; (3 bytes/element)
add AX,CX
jl y
mov BL,byte ptr reg0_pag+[DI] ; load page number for vector ptr
cmp byte ptr ptype+[BX],VECTTYPE*2 ; does it point to a vector?
jne z ; if not, error (jump)
LoadPage ES,BX ; load paragraph address for vector's page
; mov ES,pagetabl+[BX] ; load paragraph address for vector's page
mov SI,reg0_dis+[DI] ; load vector offset
add AX,offset vec_data ; add offset of 1st vector element
cmp AX,ES:[SI].vec_len ; is reference within bounds?
jge y ; if not, error (jump)
add SI,AX ; add index to vector offset
mov AL,ES:[SI].car_page ; copy vector element to destination
mov byte ptr reg0_pag+[DI],AL ; register
mov AX,ES:[SI].car
mov reg0_dis+[DI],AX
jmp next_PC ; return to the interpreter
; ***error-- offset out of bounds***
y: mov AX,offset m_v_ld
vbad_off: restore <SI> ; restore the location pointer
sub SI,DX ; and back it up to start of instruction
pushm <SI,AX> ; push LP and "VECTOR-REF/SET!" text as args
C_call disassem,,Load_ES ; disassemble instruction for *irritant*
pushm <tmp_adr,m_VOE,m_one> ; push numeric error parameters
C_call set_nume
restore <SI> ; reload next instruction's address
jmp sch_err ; link to Scheme debugger
; ***error-- invalid operand to vector-load instruction***
z: lea BX,m_v_ld
jmp src_err ; display error message
ELSE
***error*** bad macro operand
ENDIF
ENDIF
ENDIF
endm
;************************************************************************
;* AL AH *
;* Vector Load with short offset LD-VEC-S vect,offset *
;* *
;* Purpose: Scheme interpreter support for vector load instructions *
;* with short offset fields *
;************************************************************************
ld_off_s: vec_load SHORT
;************************************************************************
;* AL AX *
;* Vector Load with long offset LD-VEC-L vect,offset *
;* *
;* Purpose: Scheme interpreter support for vector load instructions *
;* with long offset fields *
;************************************************************************
ld_off_l: vec_load LONG
;************************************************************************
;* AL AH *
;* Vector Load with register offset LD-VEC-R vect,offset *
;* *
;* Purpose: Scheme interpreter support for vector load instructions *
;* with register offset fields *
;************************************************************************
ld_off_r: vec_load REG
purge vec_load
;************************************************************************
;* Macro Support for Vector Store *
;************************************************************************
vec_st macro st_type
local x,y,z
IFIDN <st_type>,<LONG>
mov [BP].save_DX,5 ; record length of this instruction
lods byte ptr ES:[SI] ; load vector pointer register
mov DI,AX ; copy pointer to TIPC register DI
lods word ptr ES:[SI] ; load fullword offset
jmp short st_v_go1 ; continue processing
ELSE
lods word ptr ES:[SI] ; load vector pointer, offset operand
mov BL,AL ; copy vector pointer register
mov DI,BX ; number into TIPC register DI
IFIDN <st_type>,<SHORT>
mov AL,AH ; convert immediate byte offset to
cbw ; a fullword value
jmp short st_v_go ; continue processing
ELSE
IFIDN <st_type>,<REG>
mov BL,AH ; copy number of index register
cmp byte ptr reg0_pag+[BX],SPECFIX*2 ; index a fixnum?
jne z ; if not, error (jump)
mov AX,reg0_dis+[BX] ; load immediate value from index register
shl AX,1 ; sign extend 15 bit immediate
sar AX,1
st_v_go: mov [BP].save_DX,4
st_v_go1: mov CX,AX ; save index value in TIPC register CX
lods byte ptr ES:[SI] ; load source register number
save <SI> ; save current location pointer
xor DX,DX ; save the source register number in
mov DL,AL ; TIPC register DX
mov AX,CX ; multiply the index value by 3
shl AX,1 ; (3 bytes/element)
add AX,CX
jl y
mov BL,byte ptr reg0_pag+[DI] ; load page number for vector ptr
cmp byte ptr ptype+[BX],VECTTYPE*2 ; does it point to a vector?
jne z ; if not, error (jump)
;;; test attrib+[BX],READONLY ; is vector's page write protected?
;;; jnz x ; if write protected, error (jump)
LoadPage ES,BX ; load paragraph address for vector's page
; mov ES,pagetabl+[BX] ; load paragraph address for vector's page
mov SI,reg0_dis+[DI] ; load vector offset
add AX,offset vec_data ; add in offset of 1st vector element
cmp AX,ES:[SI].vec_len ; is reference within bounds?
jge y ; if not, error (jump)
add SI,AX ; add index to vector offset
mov DI,DX ; copy source regsiter number into DI
mov AL,byte ptr reg0_pag+[DI] ; copy contents of source register
mov ES:[SI].car_page,AL ; into the element of the vector
mov AX,reg0_dis+[DI]
mov ES:[SI].car,AX
jmp next_PC ; return to the interpreter
;;;; ***error-- write protection violation***
;;;x: error <m_il_st>
; ***error-- offset out of bounds***
y: restore <DX>
mov AX,offset m_v_st
jmp vbad_off
; ***error-- invalid operand to vector-load instruction***
z: lea BX,m_v_st
jmp src_err ; display error message
ELSE
***error*** bad macro operand
ENDIF
ENDIF
ENDIF
endm
;************************************************************************
;* AL AH AL *
;* Vector Store with short offset ST-VEC-S vect,offset,src *
;* *
;* Purpose: Scheme interpreter support for vector store instructions *
;* with short offset fields *
;************************************************************************
st_off_s: vec_st SHORT
;************************************************************************
;* AL AX AL *
;* Vector Store with long offset ST-VEC-L vect,offset,src *
;* *
;* Purpose: Scheme interpreter support for vector store instructions *
;* with long offset fields *
;************************************************************************
st_off_l: vec_st LONG
;************************************************************************
;* AL AH AL *
;* Vector Store with register offset ST-VEC-R vect,offset,src *
;* *
;* Purpose: Scheme interpreter support for vector store instructions *
;* with register offset fields *
;************************************************************************
st_off_r: vec_st REG
purge vec_st
;;;; Load from reference cell DEREF dest
;;;deref: lods byte ptr ES:[SI] ; fetch operand, increment location pointer
;;; mov DX,ES ; save TIPC register ES
;;; mov BX,AX ; move destination register field and
;;; add BX,offset reg0 ; and compute destination reg address
;;; mov DI,[BX].C_page ; load source reg page number
;;; cmp byte ptr ptype+[DI],REFTYPE*2 ; does page contain ref cells?
;;; jne not_ref ; if not, jump (must be reference type)
;;; mov ES,pagetabl+[DI] ; load page's paragraph address
;;; mov DI,[BX].C_disp ; load source displacement into page
;;; mov AX,ES:[DI].car ; load disp at source location
;;; mov [BX].C_disp,AX ; store into destination register
;;; mov AL,ES:[DI].car_page ; load page number at source location
;;; mov byte ptr [BX].C_page,AL ; store into destination register
;;; mov ES,DX ; restore TIPC register ES (code block para)
;;; jmp next ; branch back to interpreter
;;;; error-- object of ref not a reference cell
;;;not_ref: save <SI> ; save current location pointer
;;; lea BX,m_deref
;;; jmp src_err ; display error message
;;;; Create a reference cell (ref obj)
;;;ref: lods byte ptr ES:[SI] ; load register number
;;; lea BX,[BP].temp_reg ; load address of temp register and
;;; push BX ; push as argument to "alloc_ref_cell"
;;; C_call alloc_re,<AX,SI>,Load_ES ; allocate ref cell
;;; mov SP,BP
;;; mov BX,[BP].temp_reg.C_page ; Load page number of ref cell
;;; mov ES,pagetabl+[BX] ; load paragraph address of ref cell page
;;; mov DI,[BP].temp_reg.C_disp ; load the cell's displacement
;;; mov SI,[BP].save_AX ; restore reg number from old AX into SI
;;;; copy pointer to object into newly allocated ref cell-- update dest reg
;;; mov AX,DI ; copy displacement
;;; xchg AX,reg0_dis+[SI] ; load displacement, and
;;; mov ES:[DI].car,AX ; store into new ref cell
;;; mov AX,BX ; copy page number
;;; xchg AX,reg0_pag+[SI] ; load page number, and
;;; mov ES:[DI].car_page,AL ; store it, too
;;; jmp next_PC
;************************************************************************
;* AL AH *
;* Set Reference (set_ref! ref val) SETREF ref,val *
;************************************************************************
;;;set_ref: lods word ptr ES:[SI] ; load src/dest register numbers
;;; save <SI> ; save the location pointer
;;; mov BL,AL ; copy dest register number
;;; mov DI,BX
;;; mov SI,reg0_dis+[DI] ; copy displacement of ref cell
;;; mov BL,byte ptr reg0_pag+[DI] ; copy ref cell's page number
;;; cmp byte ptr ptype+[BX],REFTYPE*2 ; it is a ref cell, isn't it?
;;; jne not_strf ; if not, error
;;; mov ES,pagetabl+[BX] ; load paragraph of ref cell's page
;;; mov BL,AH ; copy source register number
;;; mov AX,reg0_dis+[BX] ; load contents of source register and
;;; mov ES:[SI].car,AX ; and copy into ref cell
;;; mov reg0_dis+[DI],AX ; and into destination register
;;; mov AL,byte ptr reg0_pag+[BX]
;;; mov ES:[SI].car_page,AL
;;; mov byte ptr reg0_pag+[DI],AL
;;; jmp next_PC ; return to interpreter
;;;; Error-- destination of set_ref! or swap_ref! not a ref cell
;;;not_strf: error <m_setref,m_dest,m_error> ; display error message
;************************************************************************
;* AL AH *
;* Swap Reference (swap_ref! ref val) SWAPREF dest,val *
;************************************************************************
;;;swap_ref: lods word ptr ES:[SI] ; load src/dest register numbers
;;; save <SI> ; save the current location pointer
;;; mov BL,AL ; copy dest register number
;;; mov DI,BX
;;; mov SI,reg0_dis+[DI] ; copy displacement of ref cell
;;; mov BL,byte ptr reg0_pag+[DI] ; copy ref cell's page number
;;; cmp byte ptr ptype+[BX],REFTYPE*2 ; it is a ref cell, isn't it?
;;; jne not_swrf ; if not, error
;;; mov ES,pagetabl+[BX] ; load paragraph of ref cell's page
;;; mov BL,AH ; copy source register number
;;; mov AX,reg0_dis+[BX] ; load contents of source register and
;;; xchg ES:[SI].car,AX ; and exchange with contents of ref
;;; mov reg0_dis+[DI],AX ; cell
;;; mov AL,byte ptr reg0_pag+[BX]
;;; xchg ES:[SI].car_page,AL
;;; mov byte ptr reg0_pag+[DI],AL
;;; jmp next_PC ; return to interpreter
;;;not_swrf: error <m_swaprf,m_dest,m_error> ; display error message
; Negation (minus obj) MINUS dest
minus: lods byte ptr ES:[SI] ; load register field
mov DI,AX ; and copy into DI
add DI,offset reg0 ; load address of register
cmp [DI].C_page,SPECFIX*2 ; is this a fixnum?
jne minus_nf ; if not, go out of line
mov AX,[DI].C_disp ; load immediate value
shl AX,1 ; align for sign extension
minusmrg: neg AX ; negate the immediate value
jo minus_ov ; overflow? if so, make bignum
shr AX,1 ; re-align immediate value
mov [DI].C_disp,AX ; store result into register
jmp next ; return to interpreter
; Not a fixnum-- call arithmetic support
minus_nf: mov DX,MINUS_OP ; indicate negation sub-opcode
; Process unary operation out of line
arith_1: pushm <DI,DX> ; push reg addr, sub-opcode
C_call arith1,<SI>,Load_ES ; call unary arithmetic support
cmp AX,0 ; was error encountered?
jne arith_1x ; if error, jump
jmp next_SP ; process next instruction
arith_1x: jmp sch_err ; link to Scheme debugger
minus_ov: mov AX,16384 ;Create result
sub DI,offset reg0 ; Convert register addr back to reg number
; Fixnum overflow-- convert to bignum
enlrg1: cwd ; Convert to long integer
enlrg2: add DI,offset reg0 ; compute address of destination register
pushm <DX,AX,DI> ; push long int, reg addr
C_call enlarge,<SI>,Load_ES ; create bignum
jmp next_SP ; process next instruction
; Support for absolute value (abs n)
sabs: lods byte ptr ES:[SI] ; load destination register number
mov DI,AX
add DI,offset reg0 ; load register address
cmp [DI].C_page,SPECFIX*2 ; Fixnum (immediate)?
jne abs_nf ; if not, go out-of-line
mov AX,[DI].C_disp ; load immediate value
shl AX,1 ; shift to position sign bit
cmp AX,0 ; how's it relate to zero?
jl minusmrg ; if negative, negate
jmp next ; else do nothing
abs_nf: mov DX,ABS_OP ; load absolute value subopcode
jmp arith_1 ; process out of line
;************************************************************************
;* Macro support for out-of-line calls to Lattice C *
;************************************************************************
OTL_R_ = 1
OTL_RT_ = 1
OTL_R macro rtn,error_p
local x
IFNDEF rtn
extrn rtn:near
ENDIF
mov DI,offset PGROUP:rtn ; load address of routine
IFIDN <error_p>,<TEST_RESULT>
IF OTL_RT_
OTL_RT_ = 0
otlr1t: lods byte ptr ES:[SI] ; load register operand
save <SI> ; save the location pointer
add AX,offset reg0 ; compute address of register
push AX ; and push as single argument
mov AX,DS ; set ES to point to the
mov ES,AX ; current data segment
call DI ; call desired routine
cmp AX,0 ; was error detected?
jl x ; if error, jump
jmp next_SP ; return to interpreter
x: jmp sch_err ; link to Scheme debugger
ELSE
jmp otlr1t ; call desired routine
ENDIF
ELSE
IF OTL_R_
OTL_R_ = 0
otlr1: lods byte ptr ES:[SI] ; load register operand
save <SI> ; save the location pointer
add AX,offset reg0 ; compute address of register
push AX ; and push as single argument
mov AX,DS ; set ES to point to the
mov ES,AX ; current data segment
mov AX,offset PGROUP:next_SP ; push "next_SP" as the
push AX ; return address
jmp DI ; tail recursive call to routine
ELSE
jmp otlr1 ; call desired routine
ENDIF
ENDIF
endm
OTL_R2_ = 1
OTL_R2T_ = 1
OTL_R2 macro rtn,error_p
local x
IFNDEF rtn
extrn rtn:near
ENDIF
mov DI,offset PGROUP:rtn ; load address of routine
IFIDN <error_p>,<TEST_RESULT>
IF OTL_R2T_
OTL_R2T_ = 0
otlr2t: lods word ptr ES:[SI] ; load register operand
save <SI> ; save the location pointer
xor BX,BX
mov BL,AH
add BX,offset reg0 ; compute address of register
xor AH,AH
add AX,offset reg0
pushm <BX,AX> ; push register addresses as arguments
mov AX,DS
mov ES,AX
call DI ; call desired routine
cmp AX,0 ; was error detected?
jl x ; if error, jump
jmp next_SP ; return to interpreter
x: jmp sch_err ; link to Scheme debugger
ELSE
jmp otlr2t
ENDIF
ELSE
IF OTL_R2_
OTL_R2_ = 0
otlr2: lods word ptr ES:[SI] ; load register operand
save <SI> ; save the location pointer
xor BX,BX
mov BL,AH
add BX,offset reg0 ; compute address of register
xor AH,AH
add AX,offset reg0
pushm <BX,AX> ; push register addresses as arguments
mov AX,DS ; set ES to point to the current data
mov ES,AX ; segment
mov AX,offset PGROUP:next_SP ; push address of "next_SP" as
push AX ; the return address
jmp DI ; tail recursive call to desired routine
ELSE
jmp otlr2
ENDIF
ENDIF
endm
OTL_R3_ = 1
OTL_R3T_ = 1
OTL_R3 macro rtn,error_p
local x
IFNDEF rtn
extrn rtn:near
ENDIF
mov DI,offset PGROUP:rtn ; load address of routine
IFIDN <error_p>,<TEST_RESULT>
IF OTL_R3T_
OTL_R3T_ = 0
otlr3t: lods byte ptr ES:[SI] ; load 1st operand
add AX,offset reg0 ; and compute register address
mov CX,AX
lods word ptr ES:[SI] ; load 2nd and 3rd operands
save <SI> ; save the location pointer
xor BX,BX
mov BL,AH
add BX,offset reg0 ; compute address of register
xor AH,AH
add AX,offset reg0
pushm <BX,AX,CX> ; push register addresses as arguments
mov AX,DS
mov ES,AX
call DI ; call desired routine
cmp AX,0 ; was error detected?
jl x ; if error, jump
jmp next_SP ; return to interpreter
x: jmp sch_err ; link to Scheme debugger
ELSE
jmp otlr3t ; call desired routine
ENDIF
ELSE
IF OTL_R3_
OTL_R3_ = 0
otlr3: lods byte ptr ES:[SI] ; load 1st operand
add AX,offset reg0 ; and compute register address
mov CX,AX
lods word ptr ES:[SI] ; load 2nd and 3rd operands
save <SI> ; save the location pointer
xor BX,BX
mov BL,AH
add BX,offset reg0 ; compute address of register
xor AH,AH
add AX,offset reg0
pushm <BX,AX,CX> ; push register addresses as arguments
mov AX,DS
mov ES,AX
mov AX,offset PGROUP:next_SP ; push address of "next_SP" as
push AX ; the return address
jmp DI ; tail recursive call to desired routine
ELSE
jmp otlr3 ; call desired routine
ENDIF
ENDIF
endm
OTL_R4_ = 1
OTL_R4T_ = 1
OTL_R4 macro rtn,error_p
local x
IFNDEF rtn
extrn rtn:near
ENDIF
mov DI,offset PGROUP:rtn ; load address of routine
IFIDN <error_p>,<TEST_RESULT>
IF OTL_R4T_
OTL_R4T_ = 0
otlr4t: lods word ptr ES:[SI] ; load 1st and 2nd operands
xor CX,CX
xor DX,DX
mov DL,AL ; copy 1st operand register number
add DX,offset reg0
mov CL,AH ; copy 2nd operand register number
add CX,offset reg0
lods word ptr ES:[SI] ; load 3rd and 4th operands
save <SI> ; save the location pointer
xor BX,BX
mov BL,AH ; copy 4th operand register number
add BX,offset reg0 ; compute address of register
xor AH,AH
add AX,offset reg0
pushm <BX,AX,CX,DX> ; push register addresses as arguments
mov AX,DS
mov ES,AX
call DI ; call desired routine
cmp AX,0 ; was error detected?
jl x ; if error, jump
jmp next_SP ; return to interpreter
x: jmp sch_err ; link to Scheme debugger
ELSE
jmp otlr4t ; call desired routine
ENDIF
ELSE
IF OTL_R4_
OTL_R4_ = 0
otlr4t: lods word ptr ES:[SI] ; load 1st and 2nd operands
xor CX,CX
xor DX,DX
mov DL,AL ; copy 1st operand register number
add DX,offset reg0
mov CL,AH ; copy 2nd operand register number
add CX,offset reg0
lods word ptr ES:[SI] ; load 3rd and 4th operands
save <SI> ; save the location pointer
xor BX,BX
mov BL,AH ; copy 4th operand register number
add BX,offset reg0 ; compute address of register
xor AH,AH
add AX,offset reg0
pushm <BX,AX,CX,DX> ; push register addresses as arguments
mov AX,DS
mov ES,AX
mov AX,offset PGROUP:next_SP ; push address of "next_SP" as
push AX ; the return address
jmp DI ; tail recursive call to desired routine
ELSE
jmp otlr4 ; call desired routine
ENDIF
ENDIF
endm
;************************************************************************
; Convert number to fixnum (toward nearest integer) ROUND reg *
;************************************************************************
sround: OTL_R round,TEST_RESULT
;************************************************************************
; Convert number to fixnum (toward - infinity) FLOOR reg *
;************************************************************************
sfloor: OTL_R floor,TEST_RESULT
;************************************************************************
; Convert number to fixnum (toward + infinity) CEILING reg *
;************************************************************************
sceiling: OTL_R ceiling,TEST_RESULT
;************************************************************************
; Convert number to fixnum (toward zero) TRUNCATE reg *
;************************************************************************
struncat: OTL_R truncate,TEST_RESULT
;************************************************************************
; Convert number to fixnum FLOAT reg *
;************************************************************************
float: OTL_R sfloat,TEST_RESULT
;************************************************************************
;* Support for string->symbol (string->symbol dest) *
;************************************************************************
str2sym: OTL_R str_2_sy,TEST_RESULT
;************************************************************************
;* string->uninterned-symbol (string->uninterned-symbol dest) *
;************************************************************************
str2usym: OTL_R str_2_us,TEST_RESULT
;************************************************************************
;* Support for symbol->string (symbol->string dest) *
;************************************************************************
sym2str: OTL_R sym_2_st,TEST_RESULT
;************************************************************************
;* Support for fast load (fasl filename) *
;************************************************************************
sfasl: OTL_R fasl,TEST_RESULT
;;;;************************************************************************
;;;;* Support for unique symbol generation (gensym sym) *
;;;;************************************************************************
;;;gensym: OTL_R sgensym
;************************************************************************
;* Support for prop-list (prop-list name) *
;************************************************************************
proplist: OTL_R prop_lis,TEST_RESULT
;************************************************************************
;* Support for random (random seed) *
;************************************************************************
random: OTL_R srandom
;;;;************************************************************************
;;;;* Support for current-column (current-column dest) *
;;;;************************************************************************
;;;curr_clm: OTL_R current_
;;;;************************************************************************
;;;;* Support for line-length (line-length dest) *
;;;;************************************************************************
;;;line_lng: OTL_R line_len
;;;;************************************************************************
;;;;* Support for set-line-length! (set-line-length! len) *
;;;;************************************************************************
;;;set_lng: OTL_R set_line
;;;;************************************************************************
;;;;* Support for file-exists? (file-exists? string) *
;;;;************************************************************************
;;;file_ex: OTL_R file_exi
;************************************************************************
;* Support for %internal-time (%internal-time dest) *
;************************************************************************
ptyme: OTL_R ptime
;************************************************************************
;* Support for make-window (make-window dest) *
;************************************************************************
;;;mk_wind: OTL_R make_win,TEST_RESULT
;************************************************************************
;* Support for clear-window (clear-window dest) *
;************************************************************************
clr_wind: OTL_R clear_wi,TEST_RESULT
;************************************************************************
;* Support for read-char (read-char dest) *
;************************************************************************
;;;readch: OTL_R read_cha,TEST_RESULT
;************************************************************************
;* Support for close-port (close-port port) *
;************************************************************************
pclose: OTL_R spclose,TEST_RESULT
;************************************************************************
;* Support for newline (newline port) *
;************************************************************************
;;;pnewlin: OTL_R spnewlin,TEST_RESULT
;************************************************************************
;* Support for read (read port) *
;************************************************************************
;;;pread: OTL_R spread,TEST_RESULT
;************************************************************************
;* Support for print-length (print-length obj) *
;************************************************************************
;;;prt_len_: OTL_R prt_len
;************************************************************************
;* Support for %transcript (%transcript port/nil) *
;************************************************************************
;;;transcrip: OTL_R trns_chg
;************************************************************************
;* Support for read-char-ready? (read-char-ready? port) *
;************************************************************************
;;;read_cr: OTL_R rd_ch_rd,TEST_RESULT
;************************************************************************
;* Support for save-window (save-window-contents port) *
;************************************************************************
;;;sav_wind: OTL_R save_win,TEST_RESULT
;************************************************************************
;* Support for read-atom (read-atom port)*
;************************************************************************
;;;read_at: OTL_R srd_atom,TEST_RESULT
;************************************************************************
;* Support for %start-timer (%start-timer #-ticks) *
;************************************************************************
set_tim: OTL_R cset_tim,TEST_RESULT
;************************************************************************
;* Support for %stop-timer (%stop-timer) *
;************************************************************************
rst_tim: OTL_R crst_tim,TEST_RESULT
;************************************************************************
;* Support for STRING-LENGTH (STRING-LENGTH STRING) *
;************************************************************************
str_lng: OTL_R st_len,TEST_RESULT
;************************************************************************
;* Support for REIFY-STACK (REIFY-STACK index) *
;************************************************************************
reify_s: OTL_R reif_stk,TEST_RESULT
;************************************************************************
;* Support for princ (princ obj {port}) *
;************************************************************************
;;;pprinc: OTL_R2 spprinc,TEST_RESULT
;************************************************************************
;* Support for get-prop (get-prop name prop) *
;************************************************************************
getprop: OTL_R2 get_prop
;************************************************************************
;* Support for rem-prop (rem-prop name prop) *
;************************************************************************
remprop: OTL_R2 rem_prop
;************************************************************************
;* Support for get-window-attribute (get-window-attribute wind attr) *
;************************************************************************
;;;get_w_at: OTL_R2 get_wind,TEST_RESULT
;************************************************************************
;* Support for open-port (open port mode) *
;************************************************************************
popen: OTL_R2 spopen,TEST_RESULT
;************************************************************************
;* Support for prin1 (prin1 obj {port}) *
;************************************************************************
;;;pprin1: OTL_R2 spprin1,TEST_RESULT
;************************************************************************
;* Support for print (print obj {port}) *
;************************************************************************
;;;pprint: OTL_R2 spprint,TEST_RESULT
;************************************************************************
;* Support for restore-window (restore-window-contents port data) *
;************************************************************************
;;;res_wind: OTL_R2 rest_win,TEST_RESULT
;************************************************************************
;* Support for REIFY-STACK! (REIFY-STACK index value) *
;************************************************************************
reify_sb: OTL_R2 reif_stb,TEST_RESULT
;************************************************************************
;* Support for APPEND (APPEND list obj) *
;************************************************************************
append: OTL_R2 sappend,TEST_RESULT
;************************************************************************
;* Support for put-prop (put-prop name value prop) *
;************************************************************************
putprop: OTL_R3 put_prop,TEST_RESULT
;************************************************************************
;* Substring (substring string position length) SUBSTR str,pos,len *
;************************************************************************
substr: OTL_R3 ssubstr,TEST_RESULT
;************************************************************************
;* Support for set-window-attr (get-window-attribute wind attr val) *
;************************************************************************
set_w_at: OTL_R3 set_wind,TEST_RESULT
;************************************************************************
;* Support for subset-find-next-char-in-set (... str start end charset) *
;************************************************************************
srch_nx: OTL_R4 srch_nxt,TEST_RESULT
;************************************************************************
;* Support for subset-find-prev-char-in-set (... str start end charset) *
;************************************************************************
srch_pr: OTL_R4 srch_prv,TEST_RESULT
;************************************************************************
;* Interface to set file position (set-file-position! port chunk# bytes)
;************************************************************************
sfpos: OTL_R3 set_pos,TEST_RESULT
purge OTL_R,OTL_R2,OTL_R3,OTL_R4
;************************************************************************
;* AL AH AL *
;* Support for "reification" (%reify obj index) *
;* (%reify! obj index val) *
;************************************************************************
sreifyb: mov CX,1 ; set flag for "store" operation
jmp short sreif_10 ; skip next instruction
sreify: xor CX,CX ; set flag for "load" operation
sreif_10: lods word ptr ES:[SI] ; load obj,index operand register numbers
xor BX,BX
mov BL,AL ; copy obj's register number and
lea DI,reg0+[BX] ; compute obj register's address
mov BL,AH ; copy index's register number and
add BX,offset reg0 ; compute index register's address
cmp CX,0 ; is this a load or a store?
je sreif_20 ; if a load, jump
xor AX,AX
lods byte ptr ES:[SI] ; load value register number and
add AX,offset reg0 ; compute value register's address
push AX ; push value reg as argument
sreif_20: pushm <BX,DI,CX> ; push index reg, obj reg, direction
C_call reify,<SI>,Load_ES ; call: reify(dir,obj,index{,val});
cmp AX,0 ; test result of reification request
jne sreif_30 ; if error, jump
jmp next_SP ; return to interpreter
; ***error-- error status returned from reify call***
sreif_30: restore <SI> ; reload the location pointer
jmp sch_err ; link to Scheme debugger
;************************************************************************
;* Macro definition - Interpreter support for binary operations *
;* *
;* Purpose: To generate interpreter support for operations of the *
;* form: *
;* OP dest,src *
;* where: *
;* destination reg <- destination reg OP source reg *
;************************************************************************
bin_op macro operation
local label1,label2,label3,label4
lods word ptr ES:[SI] ; load destination/source register numbers
mov BL,AL ; copy destination reg number to
mov DI,BX ; register DI
mov AL,byte ptr reg0_pag+[DI] ; test to see in destination's
cmp AL,SPECFIX*2 ; page contains fixnums
jne label1 ; if not, process out of line (jump)
mov BL,AH ; copy source register number
cmp AL,byte ptr reg0_pag+[BX] ; is second operand also a fixnum?
jne label1 ; if not, process out of line (jump)
mov BX,reg0_dis+[BX] ; load source (second) operand
mov AX,reg0_dis+[DI] ; load destination (first) operand
shl AX,1 ; adjust sign bits of both
shl BX,1 ; operands
IFIDN <operation>,<ADD>
add AX,BX ; add the two operands
jo add_ov ; overflow? if so, convert to bignum (jump)
ELSE
IFIDN <operation>,<SUB>
sub AX,BX ; subtract the two operands
jo sub_ov ; overflow? if so, convert to bignum (jump)
ELSE
IFIDN <operation>,<MUL>
sar AX,1 ; divide first operand by 2
imul BX ; multiply the two operands
jo mul_ov ; overflow? if so, convert to bignum (jump)
ELSE
IFIDN <operation>,<DIV>
cmp BX,0 ; is the divisor zero?
je zero_div ; if so, error
cwd ; convert dividend to a doubleword
idiv BX ; divide the two operands
cmp DX,0 ; is remainder zero?
jne div_frac ; if so, return flonum result (jump)
shl AX,1 ; clear high order bit of result
ELSE
IFIDN <operation>,<QUOT>
cmp BX,0 ; is the divisor zero?
je zero_dvq ; if so, error
cwd ; convert dividend to a doubleword
idiv BX ; divide the two operands
shl AX,1 ; clear high order bit of result
ELSE
IFIDN <operation>,<MOD>
cmp BX,0 ; is the divisor zero?
je zero_dvm ; if so, error (jump)
cwd ; convert dividend to a doubleword
idiv BX ; divide the two operands (gives remainder)
mov AX,DX ; copy remainder to AX
ELSE
IFIDN <operation>,<MAX>
cmp AX,BX ; compare the two operands
jge max_done ; if destination operand biggest, jump
mov AX,BX ; copy the source operand to AX
ELSE
IFIDN <operation>,<MIN>
cmp AX,BX ; compare the two operands
jle max_done ; if destination operand smallest, jump
mov AX,BX ; copy the source operand to AX
ELSE
IFIDN <operation>,<XOR>
xor AX,BX ; xor the two operands
ELSE
IFIDN <operation>,<AND>
and AX,BX ; and the two operands
ELSE
IFIDN <operation>,<OR>
or AX,BX ; ior the two operands
ELSE
***error*** ; undefined instruction
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
shr AX,1 ; convert result to 15 bit value
mov reg0_dis+[DI],AX ; store result into destination register
jmp next ; return to the interpreter
IFIDN <operation>,<ADD>
label1: mov DX,ADD_OP ; load operation type
; General arithmetic support for non-interget binary arithmetic operations
; Registers at this point: AH - source register number
; BH - (zero)
; DX - arithmetic sub-opcode (operation type)
; DI - destination register number
bin_ool: mov BL,AH ; copy source register number
add BX,offset reg0 ; compute source register's address
add DI,offset reg0 ; compute destination register's address
pushm <BX,DI,DX> ; push arguments on TIPC's stack
C_call arith2,<SI>,load_ES ; process the non-integer operation
cmp AX,0 ; error encountered?
jne label4 ; if error detected, jump
jmp next_SP ; return to the interpreter
label4: jmp sch_err ; link to Scheme debugger
ELSE
IFIDN <operation>,<MAX>
label1: mov DX,GE_OP ; load operation type
max_ool: mov BL,AH ; copy source register number
add BX,offset reg0 ; compute source register's address
add DI,offset reg0 ; compute destination register's address
pushm <BX,DI,DX> ; push arguments on TIPC's stack
C_call arith2,<BX,DI,SI>,load_ES ; process the non-integer operation
cmp AX,0 ; what was the result of the comparison?
jl label3 ; if error detected, jump
jne label2 ; jump, if correct value already in dest reg
restore <BX,DI> ; restore register addresses
mov AX,[BX].C_disp ; copy source operand into the destination
mov [DI].C_disp,AX ; register
mov AL,byte ptr [BX].C_page
mov byte ptr [DI].C_page,AL
label2: jmp next_SP ; return to the interpreter
label3: jmp sch_err ; link to Scheme debugger
ELSE
IFIDN <operation>,<MIN>
label1: mov DX,LE_OP ; load operation type
jmp max_ool ; process non-integer comparison out of line
ELSE
label1: mov DX,operation&_OP ; load operation type
jmp bin_ool ; process non-integer operation out of line
ENDIF
ENDIF
ENDIF
endm
;************************************************************************
; Addition (+ obj1 obj2) ADD dest,src *
;************************************************************************
add: bin_op ADD
sub_ov: cmc ; complement the carry bit for subtract
add_ov: rcr AX,1 ; Shift in sign bit
jmp enlrg1 ; convert to bignum
;************************************************************************
;* Subtraction (- obj1 obj2) SUB dest,src *
;************************************************************************
sub: bin_op SUB
;************************************************************************
;* Multiplication (* obj1 obj2) MUL dest,src *
;************************************************************************
mul: bin_op MUL
mul_ov: sar DX,1 ;Divide product by 2
rcr AX,1
jmp enlrg2 ;Convert to bignum
;************************************************************************
;* Division (/ obj1 obj2) DIV dest,src *
;************************************************************************
div: bin_op DIV
; ***Error-- Division by Zero***
zero_div: mov BX,offset m_DIV ; load text for "\"
zd_010: sub SI,3 ; back up location pointer to start of inst.
pushm <SI,BX> ; push inst addr, function name
C_call disassem,<SI>,Load_ES ; "disassemble" the instruction
pushm <tmp_adr,m_zerodv,m_one> ; push irritant,div code,no restart
C_call set_nume ; set_numeric_error(1,ZERO_DIV,tmp_reg)
restore <SI> ; load restart address (not used)
jmp sch_err ; link to Scheme debugger
; ***Fractional Result from Division-- Convert to Flonum***
div_frac: add DI,offset reg0 ; compute destination register address
push DI ; and push as argument to "sfloat"
C_call sfloat,<SI>,load_ES ; convert destination op to flonum
les SI,dword ptr [BP].save_SI ; restore location pointer
sub SI,2 ; back up the location pointer
xor BX,BX ; clear TIPC register BX
jmp div ; re-execute div in floating point
;************************************************************************
;* Integer Division (quotient obj1 obj2) QUOTIENT dest,src *
;************************************************************************
quo: bin_op QUOT
zero_dvq: mov BX,offset m_QUOTNT ; load address of "QUOTIENT" text
jmp zd_010 ; indicate divide by zero
;************************************************************************
;* Modulo (mod obj1 obj2) MOD dest,src *
;************************************************************************
modulo: bin_op MOD
zero_dvm: mov BX,offset m_MODULO ; load address of "REMAINDER" text
jmp zd_010 ; indicate divide by zero
;************************************************************************
;* Maximum value (max obj1 obj2) MAX dest,src *
;************************************************************************
maximum: bin_op MAX
max_done: jmp next ; return to interpreter
;************************************************************************
;* Minimum value (min obj1 obj2) MIN dest,src *
;************************************************************************
minimum: bin_op MIN
;************************************************************************
;* (bitwise-xor obj1 obj2) XOR dest,src *
;************************************************************************
b_xor: bin_op XOR
;************************************************************************
;* (bitwise-and obj1 obj2) AND dest,src *
;************************************************************************
b_and: bin_op AND
;************************************************************************
;* (bitwise-or obj1 obj2) OR dest,src *
;************************************************************************
b_or: bin_op OR
purge bin_op
;************************************************************************
;* Macro definition - Interpreter support for immediate operations *
;* *
;* Purpose: To generate interpreter support for operations of the *
;* form: *
;* OP dest,immediate *
;* where: *
;* destination reg <- destination reg OP immediate *
;************************************************************************
immed_op macro operation
local label1,label2,label3,label4
lods word ptr ES:[SI] ; load destination reg/immediate value
mov BL,AL ; copy destination reg number to
mov DI,BX ; register DI
mov AL,AH ; sign extend immediate operand
cbw
cmp byte ptr reg0_pag+[DI],SPECFIX*2 ; dest operand a fixnum?
jne label1 ; if not, process out of line (jump)
mov BX,AX ; move immediate operand to BX
mov AX,reg0_dis+[DI] ; load destination (first) operand
shl AX,1 ; adjust sign bits of both
shl BX,1 ; operands
IFIDN <operation>,<ADD>
add AX,BX ; add the two operands
jo addi_ov ; overflow? if so, convert to bignum (jump)
ELSE
IFIDN <operation>,<SUB>
sub AX,BX ; subtract the two operands
jo addi_ov ; overflow? if so, convert to bignum (jump)
ELSE
IFIDN <operation>,<MUL>
sar AX,1 ; divide first operand by 2
imul BX ; multiply the two operands
jo muli_ov ; overflow? if so, convert to bignum (jump)
ELSE
IFIDN <operation>,<DIV>
cmp BX,0 ; is the divisor zero?
je zero_dvi ; if so, error
cwd ; convert dividend to a doubleword
idiv BX ; divide the two operands
cmp DX,0 ; is remainder zero?
jne divi_frc ; if not, need flonum result (jump)
shl AX,1 ; clear high order bit of result
ELSE
IFIDN <operation>,<MOD>
cmp BX,0 ; is the divisor zero?
je label2 ; if so, assume result is the dividend
cwd ; convert dividend to a doubleword
idiv BX ; divide the two operands (gives remainder)
mov AX,DX ; copy remainder to AX
label2:
ELSE
IFIDN <operation>,<MAX>
cmp AX,BX ; compare the two operands
jge mxi_done ; if destination operand biggest, jump
mov AX,BX ; copy the source operand to AX
ELSE
IFIDN <operation>,<MIN>
cmp AX,BX ; compare the two operands
jle mxi_done ; if destination operand smallest, jump
mov AX,BX ; copy the source operand to AX
ELSE
***error*** ; undefined instruction
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
shr AX,1 ; convert result to 15 bit value
mov reg0_dis+[DI],AX ; store result into destination register
jmp next ; return to the interpreter
IFIDN <operation>,<ADD>
label1: mov DX,ADD_OP ; load operation type
; General arithmetic support for non-integer immediate operations
; Registers at this point: AX - immediate value
; DX - arithmetic sub-opcode (operation type)
; DI - destination register number
bini_ool: add DI,offset reg0 ; compute address of destination register
lea BX,[BP].temp_reg ; load address of temporary register
and AX,07fffH ; mask off sign bit of immediate value
mov [BX].C_disp,AX ; and create a fixnum value in a
mov [BX].C_page,SPECFIX*2 ; temporary register
pushm <BX,DI,DX> ; push arguments on TIPC's stack
C_call arith2,<SI>,load_ES ; process the non-integer operation
cmp AX,0 ; was error detected?
jne label3 ; if error encountered, jump
jmp next_SP ; return to the interpreter
label3: jmp sch_err ; link to Scheme debugger
ELSE
IFIDN <operation>,<MAX>
label1: mov DX,GE_OP ; load operation type
maxi_ool: add DI,offset reg0 ; compute destination register's address
lea [BX].temp_reg ; load address of temporary register
and AX,07fffH ; mask off sign bit of immediate value
mov [BX].C_disp,AX ; and create a fixnum value in a
mov [BX].C_page,SPECFIX*2 ; temporary register
pushm <BX,DI,DX> ; push arguments on TIPC's stack
C_call arith2,<BX,DI,SI>,load_ES ; process the non-integer operation
cmp AX,0 ; what was the result of the comparison?
jl label4 ; if error detected, jump
jne label2 ; jump, if correct value already in dest reg
restore <BX,DI> ; restore register addresses
mov AX,[BX].C_disp ; copy source operand into the destination
mov [DI].C_disp,AX ; register
label2: jmp next_SP ; return to the interpreter
label4: jmp sch_err ; link to the Scheme debugger
ELSE
IFIDN <operation>,<MIN>
label1: mov DX,LE_OP ; load operation type
jmp maxi_ool ; process non-integer comparison out of line
ELSE
label1: mov DX,operation&_OP ; load operation type
jmp bini_ool ; process non-integer operation out of line
ENDIF
ENDIF
ENDIF
endm
;************************************************************************
;* Add immediate ADDI reg,val *
;************************************************************************
addi: immed_op ADD
addi_ov: jmp add_ov
;************************************************************************
;* Multiply Immediate MULI reg,val *
;************************************************************************
muli: immed_op MUL
muli_ov: jmp mul_ov ; convert to bignum
;************************************************************************
;* Divide Immediate DIVI reg,val *
;************************************************************************
divi: immed_op DIV
zero_dvi: jmp zero_div ; process divide by zero
divi_frc: add DI,offset reg0 ; compute destination register address
push DI ; and push as argument to "sfloat"
C_call sfloat,<SI>,load_ES ; convert destination op to flonum
les SI,dword ptr [BP].save_SI ; restore location pointer
sub SI,2 ; back up the location pointer
xor BX,BX ; clear TIPC register BX
jmp divi ; re-execute div immed in floating point
purge immed_op
;************************************************************************
;* Test for (null? obj) NULL? reg *
;************************************************************************
null_p: lods byte ptr ES:[SI] ; load number of register to test
mov BX,AX ; and copy it into BX
cmp byte ptr reg0_pag+[BX],0 ; is page number 0?
je null_t ; if register nil, jump
xor AX,AX ; set register to nil (test false)
mov byte ptr reg0_pag+[BX],AL
mov reg0_dis+[BX],AX
jmp next
null_t: mov AL,T_PAGE*2 ; set register to 't
mov byte ptr reg0_pag+[BX],AL
mov AX,T_DISP
mov reg0_dis+[BX],AX
jmp next
;************************************************************************
;* AL AH *
;* Test for eq? (pointers identical) EQ? dest,src *
;************************************************************************
eq_p: lods word ptr ES:[SI] ; load source/dest operands
mov BL,AL ; copy destination register number
mov DI,BX ; into TIPC register DI
mov BL,AH ; copy source register number
mov AX,reg0_dis+[BX] ; load page number of source operand
cmp AX,reg0_dis+[DI] ; are the displacements identical?
jne eq_p_no ; if not, jump
mov AL,byte ptr reg0_pag+[BX] ; load src operand's page number
cmp AL,byte ptr reg0_pag+[DI] ; are page numbers identical?
jne eq_p_no ; if not, jump
mov byte ptr reg0_pag+[DI],T_PAGE*2 ; they're "eq"-- set
mov reg0_dis+[DI],T_DISP ; result to 't (true)
jmp next ; return to the interpreter
; pointers are not identical-- set result to nil
eq_p_no: xor AX,AX
mov byte ptr reg0_pag+[DI],AL ; set page number and
mov reg0_dis+[DI],AX ; displacement of result register to nil
jmp next ; return to the interpreter
;************************************************************************
;* AL AH *
;* Test for eqv? (pointers identical, or numbers equal) EQ? dest,src *
;************************************************************************
eqv_p: lods word ptr ES:[SI] ; load source/dest operands
mov BL,AL ; copy destination register number
mov DI,BX ; into TIPC register DI
mov BL,AH ; copy source register number
mov AX,reg0_dis+[BX] ; load page number of source operand
cmp AX,reg0_dis+[DI] ; are the displacements identical?
jne eqv_p_no ; if not, jump
mov AL,byte ptr reg0_pag+[BX] ; load src operand's page number
cmp AL,byte ptr reg0_pag+[DI] ; are page numbers identical?
jne eqv_p_no ; if not, jump
mov byte ptr reg0_pag+[DI],T_PAGE*2 ; they're "eq"-- set
mov reg0_dis+[DI],T_DISP ; result to 't (true)
jmp next ; return to the interpreter
; pointers are not identical-- test for numbers
eqv_p_no: mov AH,BL ; copy source register number and load
mov BL,byte ptr reg0_pag+[BX] ; page number from source reg
test attrib+[BX],FIXNUMS+BIGNUMS+FLONUMS
jz eqv_p_s ; if not a number, jump
mov AX,DI ; copy destination register number and load
mov BL,byte ptr reg0_pag+[DI] ; page number from dest reg
test attrib+[BX],FIXNUMS+BIGNUMS+FLONUMS
jz eqv_p_s ; if not a number, jump
sub SI,2 ; else set ip back to operands
jmp eq_n ; and go test with "="
eqv_p_s: test attrib+[BX],STRINGS
jz eqv_p_f ; if not a string, operands aren't eqv (jump)
add DI,offset reg0 ; else compute address of destination reg
jmp short equal_p1 ; test using "equal?"
eqv_p_f: xor AX,AX
mov byte ptr reg0_pag+[DI],AL ; set page number and
mov reg0_dis+[DI],AX ; displacement of result register to nil
jmp next ; return to the interpreter
;************************************************************************
;* AL AH *
;* Test equality of s-expressions equal? dest,src*
;* *
;* Purpose: Scheme interpreter support for the testing of "equality" *
;* of two s-expressions. *
;************************************************************************
equal_p: lods word ptr ES:[SI] ; load operands to be compared
mov BL,AL ; copy destination register number
lea DI,reg0+[BX] ; and load its address
equal_p1: mov BL,AH ; copy source register number
add BX,offset reg0 ; and compute its address, too
pushm <BX,DI> ; push arguments onto TIPC's stack
C_call sequal_p,<SI>,Load_ES ; call: sequal(&dest,&src)
pop DI ; restore destination register's address
cmp AX,0 ; are operands equal? (return code not zero)
je equal_f ; if not equal, jump
mov byte ptr [DI].C_page,T_PAGE*2 ; set result register
mov [DI].C_disp,T_DISP ; to 't
jmp next_SP ; return to interpreter
equal_f: mov byte ptr [DI].C_page,AL ; set result register to nil
mov [DI].C_disp,AX
jmp next_SP ; return to interpreter
;************************************************************************
;* Macro definition - Support for attribute tests *
;************************************************************************
attr_mac macro condition
mov DX,condition ; load attribute mask for test
IFIDN <condition>,<LISTCELL>
attr_1: lods byte ptr ES:[SI] ; fetch register to test
mov BX,AX ; copy register number
mov DI,reg0_pag+[BX] ; load page number and
attr_2: mov AX,attrib+[DI] ; and fetch page's attributes
and AX,DX ; test against mask
jnz attr_3 ; if non-zero, test is true (jump)
mov byte ptr reg0_pag+[BX],AL ; set result to nil (0)
mov reg0_dis+[BX],AX
jmp next ; return to interpreter
attr_3: mov AL,T_PAGE*2 ; set result to true
mov byte ptr reg0_pag+[BX],AL
mov AX,T_DISP
mov reg0_dis+[BX],AX
jmp next ; return to interpreter
ELSE
jmp attr_1 ; continue attribute test
ENDIF
endm
; Test for (atom? obj)
atom_p: attr_mac ATOM
; Test for (char? obj)
char_p: attr_mac CHARS
; Test for (closure? obj)
closur_p: attr_mac CLOSURE
; Test for (code? obj)
code_p: attr_mac CODE
; Test for (continuation? obj)
contin_p: attr_mac CONTINU
; Test for (float? obj)
float_p: attr_mac FLONUMS
; Test for (integer? obj)
integr_p: attr_mac FIXNUMS+BIGNUMS
; Test for (number? obj)
number_p: attr_mac NUMBERS
; Test for (pair? obj)
pair_p: attr_mac LISTCELL
; Test for (port? obj)
port_p: mov DX,PORTS ; load "port" attribute bit mask
lods byte ptr ES:[SI] ; load instruction's operand
mov BX,AX ; and copy it into BX
mov DI,reg0_pag+[BX] ; load the page number of the operand
cmp DI,CON_PAGE ; is it same page as 'console?
jne attr_2 ; if not, jump
mov AX,reg0_dis+[BX] ; load the displacement of the operand
cmp AX,CON_DISP ; is it 'console?
je attr_3 ; if so, return #!true (jump)
jmp attr_2 ; if not 'console, return #!false
; Test for (proc? obj)
proc_p: attr_mac CONTINU+CLOSURE
; Test for (ref? obj)
ref_p: attr_mac REFS
; Test for (string? obj)
string_p: attr_mac STRINGS
; Test for (symbol? obj)
symbol_p: attr_mac SYMBOLS
; Test for (vector? obj)
vector_p: attr_mac VECTORS
purge attr_mac
;************************************************************************
;* Common Support for EVEN?/ODD? *
;* *
;* Input Parameters: ES:[SI] - pointer to even?/odd? instruction's *
;* operand. *
;* DX ------ text address for "EVEN?" or "ODD?" to *
;* be used to create an error message if *
;* an error is detected. *
;* *
;* Output Parameters: Zero Flag (condition code) - 0 => even number *
;* 1 => odd number *
;* *
;* Note: If an invalid operand is detected, this routine exits to the *
;* Scheme debugger. *
;************************************************************************
eo_which: lods byte ptr ES:[SI] ; load operand to even?/odd? instruction
mov BX,AX ; copy register number to BX
add BX,offset reg0 ; and compute operand register's address
cmp byte ptr [BX].C_page,SPECFIX*2 ; is operand a fixnum?
jne eo_010 ; if not a fixnum, jump
test byte ptr [BX].C_disp,1 ; test LSB of fixnum value
ret ; return to even?/odd? support
; Operand isn't a fixnum-- test for a bignum
eo_010: mov DI,[BX].C_page ; fetch operand's page number
cmp byte ptr ptype+[DI],BIGTYPE*2 ; is operand a bignum?
jne eo_020 ; if not a bignum, error (jump)
mov CX,ES ; save value in ES
LoadPage ES,DI ; load bignum;s paragraph address
; mov ES,pagetabl+[DI] ; load bignum's paragraph address
mov DI,[BX].C_disp ; load bignum's displacement
test byte ptr ES:[DI].big_data,1 ; test LSB of bignum
mov ES,CX ; restore ES register
ret ; return to even?/odd? support
; ***Error-- operand isn't an integer***
eo_020: pushm <BX,m_one,DX> ; push operands to "set_src_error"
C_call set_src_,<SI>,Load_ES ; call said
jmp sch_err ; link to Scheme debugger
;************************************************************************
;* is an integer even? even? dest *
;* *
;* Purpose: Scheme interpreter support for the even? predicate. *
;************************************************************************
even_p: mov DX,offset m_even ; load text addr, in case of error
call eo_which ; is value even or odd?
jnz eo_false ; if LSB on, jump
eo_true: mov byte ptr [BX].C_page,T_PAGE*2 ; result is #!true
mov [BX].C_disp,T_DISP
jmp next ; return to Scheme interpreter
;************************************************************************
;* is an integer odd? odd? dest *
;* *
;* Purpose: Scheme interpreter support for the odd? predicate. *
;************************************************************************
odd_p: mov DX,offset m_odd ; load text addr, in case of error
call eo_which ; is value even or odd?
jnz eo_true ; if LSB on, jump
eo_false: xor AX,AX ; create a zero value for use as #!false
mov byte ptr [BX].C_page,AL ; result is #!false
mov [BX].C_disp,AX
jmp next ; return to Scheme interpreter
;************************************************************************
;* Macro definition - Support for arithmetic testing (cond n1 n2) *
;************************************************************************
JE_OPCOD = 01110100b
JNE_OPCOD = 01110101b
JL_OPCOD = 01111100b
JGE_OPCOD = 01111101b
JLE_OPCOD = 01111110b
JG_OPCOD = 01111111b
cond_mac macro cond
local x,y,y1,z,pred_T,labelx
IFIDN <cond>,<ne>
mov DX,NE_OP ; Load "!=" sub-opcode
STORE_BYTE_IN_CS PROG,cnd_jmp,JNE_OPCOD ;Protected Mode Macro
jmp short cnd_go
ELSE
IFIDN <cond>,<l>
mov DX,LT_OP ; Load "<" sub-opcode
STORE_BYTE_IN_CS PROG,cnd_jmp,JL_OPCOD ;Protected Mode Macro
jmp short cnd_go
ELSE
IFIDN <cond>,<g>
mov DX,GT_OP ; Load ">" sub-opcode
STORE_BYTE_IN_CS PROG,cnd_jmp,JG_OPCOD ;Protected Mode Macro
jmp short cnd_go
ELSE
IFIDN <cond>,<le>
mov DX,LE_OP ; Load "<=" sub-opcode
STORE_BYTE_IN_CS PROG,cnd_jmp,JLE_OPCOD ;Protected Mode Macro
jmp short cnd_go
ELSE
IFIDN <cond>,<ge>
mov DX,GE_OP ; Load ">=" sub-opcode
STORE_BYTE_IN_CS PROG,cnd_jmp,JGE_OPCOD ;Protected Mode Macro
jmp short cnd_go
ELSE
IFIDN <cond>,<e>
mov DX,EQ_OP ; Load "=" sub-opcode
STORE_BYTE_IN_CS PROG,cnd_jmp,JE_OPCOD ;Protected Mode Macro
cnd_go: lods word ptr ES:[SI] ; load register numbers to compare
mov BL,AL ; copy n1 register number
mov DI,BX ; into DI (clear high order byte)
cmp byte ptr reg0_pag+[DI],SPECFIX*2 ; is n1 a fixnum?
jne y ; if not, perform comparison out of line
mov BL,AH ; copy n2 register number
cmp byte ptr reg0_pag+[BX],SPECFIX*2; is n2 a fixnum?
jne y1 ; jump if not
mov AX,reg0_dis+[BX] ; load n2's immediate value
mov DX,reg0_dis+[DI] ; load n1's immediate value
shl DX,1 ; adjust immediate values to sign
shl AX,1 ; extend
cmp DX,AX ; compare the two operands
cnd_jmp equ $
j&cond z ; jump if comparison is satisfied
xor AX,AX ; store '() in destination register
mov byte ptr reg0_pag+[DI],AL
mov reg0_dis+[DI],AX
jmp next ; return to interpreter
z: mov AL,T_PAGE*2 ; store 't in destination register
mov byte ptr reg0_pag+[DI],AL
mov AX,T_DISP
mov reg0_dis+[DI],AX
jmp next ; return to interpreter
; Operand(s) not fixnums-- perform comparison in C routine
y: mov BL,AH
y1: add BX,offset reg0 ; Load address of source register
add DI,offset reg0 ; Load address of destination register
pushm <BX,DI,DX> ; Push src, dest, op arguments
C_call arith2,<DI,SI>,load_ES ; Call the arithmetic processor
restore <DI>
cmp AX,0 ; test result returned from arith2
jl labelx ; jump if error condition detected
jne pred_T ; jump if comparison is "true"
mov byte ptr [DI].C_page,AL ; store '() into destination register
mov [DI].C_disp,AX
jmp next_SP ; return to interpreter
pred_T: mov byte ptr [DI].C_page,T_PAGE*2 ; set result register to 't
mov [DI].C_disp,T_DISP
jmp next_SP ; return to interpreter
labelx: jmp sch_err ; link to Scheme debugger
ELSE
***ERROR*** condition not recognized
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
endm
; Test for numeric inequality (!= n1 n2)
ne_p: cond_mac ne
; Test for numeric less than (< n1 n2)
lt_p: cond_mac l
; Test for numeric greater than (> n1 n2)
gt_p: cond_mac g
; Test for numeric less than or equal (<= n1 n2)
le_p: cond_mac le
; Test for numeric greater than or equal (>= n1 n2)
ge_p: cond_mac ge
; Test for numeric equality (= n1 n2)
eq_n: cond_mac e
purge cond_mac
;************************************************************************
;* Macro definition - Support for arithmetic testing (cond:0 n) *
;************************************************************************
cnd1_mac macro cond
local x,y,z,cnd1_T,w
IFIDN <cond>,<l>
mov DX,NEG_OP ; load negative? comparison subopcode
STORE_BYTE_IN_CS PROG,cnd1_jmp,JL_OPCOD ;Protected Mode Macro
jmp cnd1_go ; process comparison with zero
ELSE
IFIDN <cond>,<g>
mov DX,POS_OP ; load positive? comparison subopcode
STORE_BYTE_IN_CS PROG,cnd1_jmp,JG_OPCOD ;Protected Mode Macro
jmp cnd1_go ; process comparison with zero
ELSE
IFIDN <cond>,<e>
mov DX,ZERO_OP ; load zero? comparison subopcode
STORE_BYTE_IN_CS PROG,cnd1_jmp,JE_OPCOD ;Protected Mode Macro
cnd1_go: lods byte ptr ES:[SI] ; load number of register to test
mov BX,AX
cmp byte ptr reg0_pag+[BX],SPECFIX*2 ; fixnum (immediate)?
jne y ; if not, go out of line
mov AX,reg0_dis+[BX] ; load immediate value
shl AX,1 ; position sign bit-- set compare code
cmp AX,0
cnd1_jmp equ $
j&cond z ; jump if condition satisfied
xor AX,AX ; return '() in destination regsiter
mov byte ptr reg0_pag+[BX],AL
mov reg0_dis+[BX],AX
jmp next ; return to interpreter
z: mov AL,T_PAGE*2 ; return 't in destintation register
mov byte ptr reg0_pag+[BX],AL
mov AX,T_DISP
mov reg0_dis+[BX],AX
jmp next ; return to interpreter
; operand is not a fixnum-- call C routine to perform test
y: add BX,offset reg0 ; load address of destination reg
pushm <BX,DX> ; push <reg, opcode> arguments
C_call arith1,<BX,SI>,Load_ES ; link to arithmetic support
restore <BX>
cmp AX,0 ; test result returned from "arith1"
jl w ; was error encountered?
jne cnd1_T ; if error, jump
mov byte ptr [BX].C_page,AL ; set result to "nil"
mov [BX].C_disp,AX
jmp next_SP ; return to interpreter
cnd1_T: mov byte ptr [BX].C_page,T_PAGE*2 ; set result to "t"
mov [BX].C_disp,T_DISP
jmp next_SP ; resume interpretation
w: jmp sch_err ; link to Scheme debugger
ELSE
***ERROR*** invalid comparison type
ENDIF
ENDIF
ENDIF
endm
; Test for equality to zero (zero? n)
eq_z_p: cnd1_mac e
; Test for less than zero (negative? n)
lt_z_p: cnd1_mac l
; Test for greater than zero (positive? n)
gt_z_p: cnd1_mac g
purge cnd1_mac
;************************************************************************
;* (ascii->char n) ascii->char dest *
;* *
;* Purpose: Scheme interpreter support for the ascii->char function. *
;************************************************************************
asc_char: lods byte ptr ES:[SI] ; load operand
mov DI,AX ; copy dest register number into DI
cmp byte ptr reg0_pag+[DI],SPECFIX*2 ; is operand a finxum?
jne asc_cher ; if not, error (jump)
and reg0_dis+[DI],00ffH ; "and" off low order eight bits
mov byte ptr reg0_pag+[DI],SPECCHAR*2 ; convert to character
jmp next ; return to interpreter
asc_cher: save <SI> ; save the incremented location pointer
lea BX,masc_ch ; load address of "ascii->char" text
jmp src_err ; display invalid operand message
;************************************************************************
;* (char->ascii n) char->ascii dest *
;* *
;* Purpose: Scheme interpreter support for the char->ascii function. *
;************************************************************************
char_asc: lods byte ptr ES:[SI] ; load operand
mov DI,AX ; copy dest register number into DI
cmp byte ptr reg0_pag+[DI],SPECCHAR*2 ; is operand a char?
jne ch_ascer ; if not, error (jump)
mov byte ptr reg0_pag+[DI],SPECFIX*2 ; convert to a fixnum
jmp next ; return to interpreter
ch_ascer: save <SI> ; save the incremented location pointer
lea BX,mch_asc ; load address of "char->ascii" text
jmp src_err ; display invalid operand message
;************************************************************************
;* Support for list length (length list) *
;************************************************************************
slength: lods byte ptr ES:[SI] ; load register containing list header
mov BX,AX
save <SI> ; save the program counter
lea DI,reg0+[BX] ; load the address of the dest reg
mov BX,[DI].C_page ; load list header from src/dest reg
mov SI,[DI].C_disp
xor AX,AX ; zero the counter
mov CX,SB_CHECK ; load shift-break iteration count
slenloop: cmp BL,NIL_PAGE*2 ; pointer to nil?
je slendone
cmp byte ptr ptype+[BX],LISTTYPE*2 ; list pointer?
jne slendone
inc AX ; increment list cell count
LoadPage ES,BX ; load list cell page para address
; mov ES,pagetabl+[BX] ; load list cell page para address
mov BL,ES:[SI].cdr_page ; load cdr of list cell
mov SI,ES:[SI].cdr
loop slenloop ; cdr down list
; Every so many iterations, check the shift-break key
mov CX,SB_CHECK ; reload the shift-break iteration count
cmp s_break,0 ; has the shift-break key been depressed?
je slenloop ; if no interrupt, continue (jump)
slen_sb: mov AX,2 ; load instruction length = 2
jmp restart1 ; link to Scheme debugger
slendone: mov byte ptr [DI].C_page,SPECFIX*2 ; return result as a
mov [DI].C_disp,AX ; fixnum (immediate)
jmp next_PC ; return to interpreter
;************************************************************************
;* Support for Last-pair (last-pair list) *
;************************************************************************
lst_pair: lods byte ptr ES:[SI] ; load src/destination register
save <SI> ; save the interpreter's program counter
mov DI,AX
mov BX,reg0_pag+[DI] ; load register's page number field
cmp BL,NIL_PAGE*2 ; null pointer?
je lst_exit ; if so, do nothing
cmp byte ptr ptype+[BX],LISTTYPE*2 ; does reg point to list cell?
jne lst_exit ; if not, return it as is
mov SI,reg0_dis+[DI] ; load register's displacement
xor DX,DX
mov CX,SB_CHECK ; load the shift-break iteration count
lst_loop: LoadPage ES,BX ; load page's paragraph address
; mov ES,pagetabl+[BX] ; load page's paragraph address
mov DL,ES:[SI].cdr_page ; load page number of cdr pointer
cmp DL,NIL_PAGE*2 ; cdr nil?
je lst_done ; if so, return current pointer
mov DI,DX ; copy cdr's page number
cmp byte ptr ptype+[DI],LISTTYPE*2 ; cdr points to list cell?
jne lst_done ; if not, we're at the end of our list
mov BL,DL ; follow linked list
mov SI,ES:[SI].cdr
loop lst_loop
; Every so many iterations, check the shift-break key
mov CX,SB_CHECK ; reload the shift-break iteration count
cmp s_break,0 ; has the shift-break key been depressed?
je lst_loop ; if no interrupt, continue (jump)
jmp slen_sb ; link to Scheme debugger
lst_done: mov DI,AX ; re-load destination register number
mov byte ptr reg0_pag+[DI],BL ; store page number
mov reg0_dis+[DI],SI ; store displacement
lst_exit: jmp next_PC ; return to interpreter
;************************************************************************
;* (reverse! list) reverse! dest *
;* *
;* Purpose: Scheme interpreter support for the reverse! primitive *
;* *
;* Notes: The following registers are used by this routine: *
;* BL - page number of the current list cell *
;* DI - displacement of the current list cell *
;* ES - paragraph address of the current list cell *
;* Note: ES:[DI] address the current list cell *
;* DL - page number of the previous list cell *
;* AX - displacement of the previous list cell *
;* SI - destination register number *
;************************************************************************
public reverseb
reverseb: lods byte ptr ES:[SI] ; load operand containing list pointer
save <SI> ; preserve the location pointer
mov BL,AL ; copy number of operand register
mov SI,BX ; and put a copy into TIPC register SI
mov BL,byte ptr reg0_pag+[SI] ; load contents of operand register
mov DI,reg0_dis+[SI] ; for initial "current cell" pointer
xor AX,AX ; define previous list cell to be 'nil
xor DX,DX
rev_lp: cmp BL,0 ; end of list (current cell nil)?
je rev_done ; if so, jump
cmp byte ptr ptype+[BX],LISTTYPE*2 ; is current cell a list cell?
jne rev_huh ; if not, error (jump)
LoadPage ES,BX ; load current cell's page address
; mov ES,pagetabl+[BX] ; load current cell's page address
xchg ES:[DI].cdr_page,DL ; swap cdr field with previous cell
xchg ES:[DI].cdr,AX ; pointer
xchg BX,DX ; current cell <-> (cdr current cell)
xchg DI,AX
jmp rev_lp ; continue down list
; list reversal complete-- update destintation register
rev_done: mov byte ptr reg0_pag+[SI],DL ; make destination register point
mov reg0_dis+[SI],AX ; to new head of (reversed) list
jmp next_PC ; return to the interpreter
; ***error-- not a valid linked list***
rev_huh: mov byte ptr reg0_pag+[SI],DL ; make destination register point
mov reg0_dis+[SI],AX ; to new head of (reversed) list
lea BX,m_revb
jmp src_err ; display error message
IFNDEF PROMEM
; Real mode scheme has graphics linked in with the vm (see graphics.exe),
; and can therefore call it directly. Protected mode scheme must xfer
; to a real mode graphics routine - see PROIO.asm.
;************************************************************************
;* Interface to Graphic Primitives (%graphics arg1 ... arg7) *
;************************************************************************
sgraph: mov CX,7 ; load counter-- seven arguments
xor DX,DX ; set error flag = FALSE
lods byte ptr ES:[SI] ; load first argument
save <AX> ; and save as destination register
jmp short sgraph0
sgraph1: lods byte ptr ES:[SI] ; load next argument
sgraph0: xor AH,AH ; be sure high byte is zero
mov BX,AX ; copy register number to BX
cmp byte ptr reg0_pag+[BX],SPECFIX*2 ; is arg a fixnum?
je sgraph2 ; if arg *is* a fixnum, o.k. (jump)
inc DX ; indicate an invalid argument
sgraph2: mov AX,reg0_dis+[BX] ; expand 15-bit signed int to 16-bit signed int
shl AX,1
sar AX,1
push AX ; push 16-bit signed integer
;sgraph2: push reg0_dis+[BX] ; push immediate value of argument
loop sgraph1 ; continue 'til all arguments processed
cmp DX,0 ; any argument errors?
jne sgraph3 ; if errors encountered, jump
save <SI> ; save the location pointer
;;; the following two lines are comment out
;;; allow graphics mode for unknown PC machine
;;; cmp PC_MAKE,UNKNOWN ; running on a TIPC?
;;; je not_pc ; if not a TI or IBM brand PC, jump
call graphit ; perform the graphics operation
shl AX,1 ; clear high order bit of result
shr AX,1 ; (convert to immediate value)
mov BX,[BP].save_AX ; reload destintation register number
mov reg0_dis+[BX],AX ; store returned result into destination reg
not_pc: jmp next_SP ; return to interpreter
sgraph3: mov BX,offset m_graph ; load addr of "%graphics" text
jmp src_err ; link to Scheme debugger
ENDIF
;************************************************************************
;* Interface to XLI external escape *
;* (%xesc length nargs "name" arg1 ... arg16) where argx is optional *
;* length = # args *to %xesc instruction* *
;************************************************************************
xesc: lods byte ptr es:[si] ;get xesc length (variable-length inst.);
;afterwards, bytecode@ (ES:SI) points
;at name string
xor ah,ah
mov dx,si ;tempsave bytecode@ to name string
add si,ax ;get ptr to next opcode
dec si
save <es,si>
mov si,dx ;restore bytecode@ to name string
call xli_xesc ;do xesc
restore <es,si> ;ES:SI is next opcode @
cmp ax,0 ;any errors?
jne xesc_10 ;yes, jump
jmp next ;return to interpreter
; normal errors - ax=error number, bx=irritant
xesc_10:
xchg bx,ax ;now ax=irritant,bx=error message
shl bx,1 ;make message# into index
mov bx,xli_err[bx] ;bx => error message
mov cx,1 ;cx = 1, error non-restartable
pushm <ax,bx,cx>
mov ax,ds
mov es,ax ;Lattice C needs DS=ES
C_call set_erro ;set up error
jmp sch_err ;jump into debugger
;************************************************************************
;* ******************************************************************** *
;* * * *
;* * Error routines * *
;* * * *
;* ******************************************************************** *
;************************************************************************
IFDEF PROMEM
;
; Engine timer support for protected mode
;
set_args struc
dw ?
dw ?
hi dw ?
lo dw ?
set_args ends
public settimer
; initialize the timer, set up the engine tick vm loop, and begin
settimer proc near
xor ax,ax ;clear ax
cmp tickstat,-1 ;check for normal run mode
jne no_set ;abort if timeout or engine running
push bp
mov bp,sp
mov ax,[bp].hi ;initialize the timer
mov hi_time,ax
mov ax,[bp].lo
mov lo_time,ax
mov ax,word ptr cs:eng_tick ;ax = handle to engine loop
XCHG_WORD_IN_CS PROG,next1,ax ;int loop now jumps to engine loop
STORE_WORD_IN_CS PROG,reset_tim,ax ;save original value in reset_tim
mov al,1
mov tickstat,al ;denote engine now running
pop bp
no_set: ret
settimer endp
public rsttimer
; reset vm loop to original vm loop and return whats left in timer
rsttimer proc near
cmp tickstat,1 ;only if timeout or engine running
ja no_reset ;otherwise, forget it
mov ax,cs:reset_tim ;get inst saved at top of vm loop
STORE_WORD_IN_CS PROG,next1,AX ;reset forced branch at top (next1)
mov tickstat,-1 ;no engine running
no_reset:
mov ax,hi_time ;return time left
mov bx,lo_time
ret ;return
rsttimer endp
ENDIF
;************************************************************************
;* Timer Ran Down *
;************************************************************************
; Note: the "reset_tim" variable must be in the code segment 'cause
; there's no telling where the DS register points when a
; timer interrupt occurs.
reset_tim dw 0 ; save area for resetting a timer int
public timeout
timeout:
IFNDEF PROMEM
mov AX,CS:reset_tim ; for real mode scheme, reset forced
STORE_WORD_IN_CS PROG,next1,AX ; branch at top of vm loop
ENDIF
C_call rsttimer ; turn off the timer support
mov BX,TIMEOUT_CONDITION ; load "timeout" error code
time_1: xor AX,AX ; set code for "restartable" operation
time_2: mov CX,offset nil_reg ; set *irritant* to 'nil
time_3: pushm <CX,BX,AX> ; push arguments to call
C_call set_nume,<SI>,Load_ES ; call: set_numeric_error(1,13,nil_reg)
restore <SI> ; load next instruction's offset
jmp sch_err ; link to Scheme debugger
;************************************************************************
;* Shift-Break Interrupt *
;************************************************************************
sc_debug: mov AX,CS:reset_sb ; reset forced branch at top
STORE_WORD_IN_CS PROG,next1,AX ; of vm loop
mov s_break,0 ; reset shift-break flag
mov BX,SHIFT_BREAK_CONDITION ; load "shift-break" error code
jmp time_1 ; complete link to Scheme debugger
;************************************************************************
;* DOS fatal I/O error process *
;************************************************************************
public dos_err
dos_err: pop AX ; dump return address
pop AX ; restart/non-restart flag
pop BX ; error code
pop CX ; *irritant*
mov BP,reset_BP ; clean up stack
jmp time_3 ; go invoke Scheme debugger
;************************************************************************
;* Error-- Undefined Opcode *
;************************************************************************
not_op: dec SI ; back up location pointer
save <SI> ; and save it
mov BX,offset m_not_op ; load address of error message
mov byte ptr tmp_page,SPECFIX*2 ; convert opcode to a fixnum
mov tmp_disp,AX ; representation for use as "irritant"
mov AX,offset tmp_reg
jmp recom_1 ; jump to common processing point
;************************************************************************
;* Error-- Invalid Source Operand *
;************************************************************************
public src_err
; Note: at this point, BX contains the address for text of failing inst.
src_err: xor AX,AX ; AX <- 0
pushm <AX,BX> ; push string address, 0
C_call set_src_,,Load_ES ; call: set_src_err(text, 0);
jmp sch_err ; link to Scheme debugger
;************************************************************************
;* Error-- Object Module Not Compatible With Current Revision Level *
;************************************************************************
recompil: mov AX,offset nil_reg
mov BX,offset m_recomp
recom_1: mov CX,1
pushm <AX,BX,CX>
C_call set_erro ; set the error parameters
restore <SI> ; reload the current location pointer
jmp sch_err ; link to Scheme debugger
;************************************************************************
;* Error-- Feature Not Yet Implemented *
;************************************************************************
public not_yet
not_yet: mov BX,offset m_not_yt ; load address of "not yet implemented"
push BX ; and push as argument to printf
dec SI ; back up location pointer
save <SI> ; and save it
; ***general call to printf for message reporting***
public printf_c
printf_c: C_call printf,,Load_ES ; call printf
mov SP,BP ; dump arguments off stack
restore <SI> ; reload location pointer into SI
jmp debug ; begin debug mode
;************************************************************************
;* Force Restart of Current Operation *
;************************************************************************
public restart
restart: pop AX ; discard the return address
pop AX ; fetch instruction length
mov BP,reset_BP ; clean up the TIPC's stack
restart1: sub [BP].save_SI,AX ; back up the instruction pointer
jmp next_SP ; return to the Scheme interpreter
;************************************************************************
;* Link to the Scheme Debugger *
;************************************************************************
public sch_err
sch_err: push SI ; save address of instruction to retry
call force_ca ; force a new stack frame to be built
mov SP,BP ; drop argument from TIPC's stack
mov BX,SPECCODE*2 ; load code base pointer for debug init
mov byte ptr CB_pag,BL
mov CB_dis,0
LoadCode ES,BX ; load code base's paragraph address
; mov ES,pagetabl+[BX] ; load code base's paragraph address
save <ES> ; and save it off
mov SI,ERR_ent ; load error entry point offset
jmp next ; begin link to debugger
;************************************************************************
;* Scheme-Reset/Reset *
;* *
;* Purpose: To re-initialize the VM's environment to correct for *
;* some error condition *
;************************************************************************
public force_re
force_re: mov BP,reset_BP ; reset TIPC stack to its initial state
; Note: control falls through to the scheme-reset code below
s_reset: C_call scheme_r,,Load_ES ; Adjust fluid environment
; Note: control falls through the reset code below
reset: C_call reset_fa,,Load_ES ; reset %fasl input data structures
xor AX,AX ; create a value of zero/nil
; set the "previous stack segment" register to nil
mov PREV_pag,AX
mov PREV_dis,AX
; set the current code base to the loader's code page
mov CB_dis,AX
mov CB_pag,SPECCODE*2
; reset the current stack base to zero and initialize FP
mov BASE,AX
mov FP,AX
mov TOS,SF_OVHD-PTRSIZE
; set the location pointer and code paragraph address
mov BX,SPECCODE*2
LoadCode ES,BX
; mov ES,pagetabl+[BX]
save <ES>
mov SI,RST_ent ; load the new location pointer
; Note: Control falls through the %clear-registers support below
;************************************************************************
;* Clear VM registers clear-regs *
;************************************************************************
clr_regs: save <SI> ; save the current location pointer
mov BX,UN_DISP ; load pointer for "unbound" symbol
mov DX,UN_PAGE*2
mov CX,NUM_REGS-2 ; load iteration count
mov DI,offset reg0+(SIZE C_ptr)*2 ; load address of VM register 2
mov AX,DS ; set TIPC register ES to point to the
mov ES,AX ; current data section
clr_loop: mov AX,BX ; copy '**unbound** displacement pointer
stosw ; and store it into next register
mov AX,DX ; do likewise for the page number component
stosw ; for the '**unbound** symbol
loop clr_loop ; iterate through the VM's registers
xor AX,AX
mov DI,offset reg0 ; store #!false into R0 and R1
mov CX,4
rep stosw
mov tmp_disp,AX ; clear the VM's temporary register, too
mov tmp_page,AX
mov tm2_disp,AX ; clear the VM's temporary register, too
mov tm2_page,AX
jmp next_PC ; return to the interpreter
;************************************************************************
;* Escape to user defined assembly language or C Function %escn *
;************************************************************************
s_esc1: mov CX,1 ; load argument count
jmp short s_escn ; branch to general argument load routine
s_esc2: mov CX,2 ; load argument count
jmp short s_escn ; branch to general argument load routine
s_esc3: mov CX,3 ; load argument count
jmp short s_escn ; branch to general argument load routine
s_esc4: mov CX,4 ; load argument count
jmp short s_escn ; branch to general argument load routine
s_esc5: mov CX,5 ; load argument count
jmp short s_escn ; branch to general argument load routine
s_esc6: mov CX,6 ; load argument count
jmp short s_escn ; branch to general argument load routine
public s_esc7
s_esc7: mov CX,7 ; load argument count
jmp short s_escn ; branch to general argument load routine
s_escn: mov DX,CX ; copy count of arguments
s_es_10: xor AX,AX
lods byte ptr ES:[SI] ; load next argument register number
add AX,offset reg0
push AX
loop s_es_10 ; continue 'til all arguments processed
push DX ; push number of arguments
IFDEF PROMEM
;
; This is pretty kludgy, but there wasn't time to redo all the %esc
; functions into vm codes, and we need software interrupt to work
; as before. Anyway, sw-int is the only %escape function with seven
; arguments, so lets short circuit here and call the protected mode
; software interrupt code.
;
cmp dx,7 ;are there seven arguments?
jne s_es_12 ; no, can't be sw_int
save <SI> ;save off instruction pointer
call softint ;and call the pro mode sw_int routine
cmp ax,0 ;any errors?
je s_es_20 ; no, jump
; errors - ax=error number, bx=msg address, cx=irritant
pushm <cx,bx,ax> ;push args to error routine
mov ax,ds
mov es,ax ;Lattice C needs DS=ES
C_call set_erro ;call error routine
restore <SI> ;restore instruction pointer
jmp sch_err ;and jump to scheme debugger
ENDIF
s_es_12:
C_call asm_link,<SI>,Load_ES
s_es_13:
cmp AX,0
je s_es_20
restore <SI> ; restore address of next instruction
mov BX,offset m_esc
jmp src_err ; report some sort of operand error
s_es_20: jmp next_SP ; no error reported; return to interpreter
;************************************************************************
;* (%str-append str1 start1 end1 {nil,char,str2} str3 start3 end3) *
;************************************************************************
s_append: jmp str_apnd ; far jump to substring-append support
;************************************************************************
;* (%substring-display str start end row-displacement window) *
;************************************************************************
public s_disply ; ***temporary***
s_disply: jmp str_disp ; far jump to substring-display support
;************************************************************************
;* Invoke garbage collection gc *
;************************************************************************
gc: mov byte ptr tmp_page,0 ; clear tmp_reg prior to GC
mov tmp_disp,0
mov byte ptr tm2_page,0 ; clear tm2_reg prior to GC
mov tm2_disp,0
C_call garbage,<SI>,Load_ES ; call garbage collection driver
jmp next_SP
;************************************************************************
;* Invoke garbage collection with compaction gc2 *
;************************************************************************
sgc2: mov byte ptr tmp_page,0 ; clear tmp_reg prior to GC
mov tmp_disp,0
mov byte ptr tm2_page,0 ; clear tm2_reg prior to GC
mov tm2_disp,0
C_call garbage,<SI>,Load_ES ; call garbage collection driver
C_call gcsquish
jmp next_SP
;************************************************************************
;* Begin Debug %begin-debug *
;************************************************************************
public debug_op
debug_op: mov VM_debug,1 ; enable VM debugger for (%begin-debug)
debug:
mov AX,word ptr CS:trc_go ; modify interpreter to enable instr.
STORE_WORD_IN_CS PROG,next1,AX ; Protected Mode Macro
mov s_break,0 ; reset shift-break flag
mov AX,2 ; set return value = 2 (begin debug)
jmp short exit_010
exit_op: dec SI ; back up PC to won't fall past end
mov AX,1 ; set return value = 1 (halt)
jmp short exit_010
exit: xor AX,AX ; set return value = 0 (suspend)
exit_010: mov SP,BP
mov BX,[BP].cod_ent
mov [BX],SI
add SP,offset sint_BP
pop BP
mov DX,DGROUP
mov ES,DX
ret
run endp
prog ends
end