;******************************************************************************* ; Math-related macros used in conjunction with stakmath.sub library ; Common macros for all stakmath library operations (some not to be called directly) ;******************************************************************************* _signed_ macro #ifndef SIGNED #Warning SIGNED \@~mfilename~\@ expected #endif endm ;------------------------------------------------------------------------------- _StkMthMax_ macro Expression mset # mtrim 1 #temp mdo mset 0,~'=()+-*\/&|^><'{:mloop}~ mtrim 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifparm ~text.1.1~~text.{:text}~ = [] mset 0,~text.2.{:text-2}~ #endif mset 0,~text,~ ;;remove possible index ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifparm ~text.1.1~ = # mset 0,~text.2~ ;;remove # from number #endif #ifnb ~text~ #ifnb ~text.1.1~ = . #Warning Pointers (~text~) have unknown size #endif #ifnum ~text~ ;estimate byte size for numeric constant #ifnz ~text~>16 #if 3 > :temp #temp 3 #endif #endif #ifnz ~text~>24 #if 4 > :temp #temp 4 #endif #endif #endif #ifb ~text.1.1~ = : #ifnonum ~text~ #ifdef ~text~ #if {::~text~} > :temp #temp ::~text~ #endif #endif #endif #endif #endif mloop {:1/2} ;;max term/factor estimate #ifz :temp #Warning Undetermined bit-size (using 32-bit) #temp 4 #endif ; #ifb \@~'*'~\@ = \@~1~\@ ;if any multiplication is present ; #if :temp < 4 ; #temp :temp+1 ;give some more bits (normally double, but on average this is OK) ; #endif ; #endif #if :temp > 8 ;for exceptional cases, enforce #temp 8 ;maximum available bit-size #endif @_FindStkMth_ {:temp*8} endm ;------------------------------------------------------------------------------- ; Default version -- works with signed/unsigned operands ; (In :MEXIT, it returns the actual bit-size used) Eval macro Expression #push #HideMacros mset # mtrim 1 @@_StkMthMax_ ~1~ #temp :mexit @@_FindStkMth_ {:temp} #temp :mexit @@Eval{:temp} ~1~ mset 0,{:spcheck},{:spfree-:ais},{:ais} #pull #ifspauto #spauto ~text,~ #spadd ~text','2~ #ais #spadd ~text','3~ #endif mexit {:temp} endm ;------------------------------------------------------------------------------- ; Signed version -- gives warning to alert you if SIGNED was not defined ; (In :MEXIT, it returns the actual bit-size used) EvalS macro Expression mset # @@_signed_ @Eval ~1~ endm ;------------------------------------------------------------------------------- StrMath macro #ifnb ~1~ #ifdef ~1,~ #ifnz ::~1,~ @_DoStr {::~1,~*8}\,~1~\,~2~ mexit #endif #endif #endif mset # mtrim 1 @@_StkMthMax_ ~1,~ #temp :mexit @_DoStr {:temp}\,~1~\,~2~ endm ;------------------------------------------------------------------------------- _FindStkMth_ macro BitVersion #temp mdo ~1~/8 ;;find the next highest bit version included (but not less than requested) #ifdef _STKMTH{:mloop*8}_ #ifz :temp #temp :mloop*8 ;;found #endif #endif mloop 8 ;;highest possible is 64 (8x8) #ifz :temp mstop Include STKMTH{~1~}.SUB (or higher) #endif mexit :temp endm ;------------------------------------------------------------------------------- _Eval_ macro [BitSize,]Expression (eg. [ans=](a+b)*(a-b)/2) #if :macronest = 1 mstop Macro not to be called directly (eg. use @Eval32) #endif #ifb ~00~ = ~0~ @@_needs_spauto_ mdef 1,32 mswap 0,1 ;;bitsize now in ~ text ~ mdel 1 mset # @@Msg -------------------------------------------------- @@Msg Expr: ~1~ @@Msg -------------------------------------------------- @@_FindStkMth_ ~text~ mset 0,{:mexit},~text~ ;;(bitsize to use, actual bitsize) #endif mset # mreq 1:Expression (eg. [ans=](a+b)*(a-b)/2 -- spaces OK) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifb ~00~ = ~0~ mtrim 1 ;;remove all spaces mset #'=' ;;split on assignment (if any) #if :nn > 2 mstop Too many assignment operators #endif #if :nn > 1 @@~0~ ~2~ ;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;- mset 9 ;;assume signed (when SIGNED) #ifparm ~1.1.1~~1.{:1}~ = [] mset 9,unsigned mset 1,~1.2.{:1-2}~ #endif ;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;-;- #ifparm ~1.1.1~ = . ;;pointers ... #if ~text,~/8 <> ~text','2~/8 @@ResizeTOS #~text,~/8\,#~text','2~/8\,\,~9~ @@lea ~1~ @@_?sei_ ~1~ @@pullv ~1~ ~text','2~/8 ;;are resized and then pulled @_?cli_ ~1~ mexit #endif #endif #ifdef ~1,~ ;;if assignment var defined @Save~text,~ ~1~ ;;save to it mexit #endif #ifparm ~,1~ = ,spx ;;SPX is SP-equivalent in EVAL mset 1,~1,~,sp ;;change to SP-index #endif #ifparm ~,1~ = ,sp ;;else, if SP-indexed ~1,~ equ ::,~text,~/8 ;;leave on stack with this name @@Msg Saved to TOS (~1,~) mexit #endif merror Unknown variable \@~1~\@ #endif #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifstr ~1~ #if :1-2 > 4 mstop String constant (~1~) too long #endif @Load~text,~ #~1~ mexit #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifparm ~1.1.1~ = - ;;process leading negative #ifnum ~1~ @Load~text,~ #~1~ ;;numerics use immediate mode mexit #endif #ifdef ~1.2~ #ifz ::~1.2~ @Load~text,~ #~1~ ;;named constants use immediate mode mexit #endif #endif @~0~ #0~1~ ;;anything else, subtract from zero mexit #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mset #'+-|^' ;;split terms #if :nn > 1 mdo 2 @@~0~ ~{:nn-:mloop+2}.2~ ;;process terms right to left mloop :nn @@~0~ ~1~ ;;the first term without operator mdo 2 #ifparm ~{:mloop}.1.1~ = + @@Msg Add~text,~ call StackAdd~text,~ #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = - @@Msg Sub~text,~ call StackSub~text,~ #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = | @@Msg Or~text,~ call StackOr~text,~ #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = ^ @@Msg Xor~text,~ call StackXor~text,~ #spadd -{~text,~/8} #endif mloop :nn mexit #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mset #'*\/&><' ;;split factors #if :nn > 1 mdo 2 @@~0~ ~{:nn-:mloop+2}.2~ ;;process factors right to left mloop :nn @@~0~ ~1~ ;;the first factor without operator mdo 2 #ifparm ~{:mloop}.1.1~ = * @@Msg Mul~text,~ call StackMul~text,~ #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = / @@Msg Div~text,~ call StackDiv~text,~ #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = \ @@Msg Mod~text,~ call StackMod~text,~ #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = & @@Msg And~text,~ call StackAnd~text,~ #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = > @@Msg Shr~text,~ call StackShr~text,~ #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = < @@Msg Shl~text,~ call StackShl~text,~ #spadd -{~text,~/8} #endif mloop :nn mexit #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifparm ~1.1.4~~1.{:1}~ = NEG() ;;do NEG(ate) function @@~0~ ~1.5.{:1-5}~ @@Msg Neg~text,~ call StackNegate~text,~ mexit #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifparm ~1.1.4~~1.{:1}~ = ABS() ;;do ABS(olute) function @@~0~ ~1.5.{:1-5}~ @@Msg Abs~text,~ call StackAbs~text,~ mexit #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifparm ~1.1.4~~1.{:1}~ = SQR() ;;do SQR() function -- square @@~0~ ~1.5.{:1-5}~ @@Msg Sqr~text,~(TOS) tsx call StackLoad~text,~ call StackMul~text,~ mexit #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifparm ~1.1.1~~1.{:1}~ = () ;;process parenthesized sub-expression @~0~ ~1.2.{:1-2}~ mexit #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mset 9 ;;assume signed (when SIGNED) #ifparm ~1.1.1~~1.{:1}~ = [] mset 9,unsigned mset 1,~1.2.{:1-2}~ #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifnum ~#1~ mset 1,#~#1~ ;;numerics use immediate mode #endif #ifparm ~1.1.2~ = -: mset 1,#~1~ ;;negative internal symbol use immediate #endif #ifparm ~1.1.1~ = : mset 1,#~1~ ;;positive internal symbol use immediate #endif #ifb ~,1~ #ifdef ~#1~ #ifz ::~#1~ mset 1,#~#1~ ;;named constants use immediate #endif #endif #endif #ifparm ~,1~ = ,spx ;;SPX is SP-equivalent in EVAL mset 1,~1,~,sp ;;change to SP-index #endif #ifparm ~1.1.1~ = . ;;pointers ... #if ~text','2~/8 <> ~text,~/8 @@_?sei_ ~1~ @@pushv ~1~ ~text','2~/8 ;;are pushed and then resized @@_?cli_ ~1~ @ResizeTOS #~text','2~/8\,#~text,~/8\,\,~9~ mexit #endif #endif #ifnb ~9~ mset 1,[~1~] #endif @Load~text,~ ~1~ ;;anything else, load as is endm ;------------------------------------------------------------------------------- Comp macro Exp1 Exp2 mset #' ' mreq 1,2:Exp1 Exp2 #push #spauto :sp push #ais @@Eval a$$$,sp = ~1~ @@Eval b$$$,sp = ~2~ @@_cmp_.s a$$$,sp b$$$,sp ais #:ais pull #pull endm ;------------------------------------------------------------------------------- Eval8 macro mset # @_Eval_ ~0.5~\,~1~ endm ;------------------------------------------------------------------------------- Eval16 macro mset # @_Eval_ ~0.5~\,~1~ endm ;------------------------------------------------------------------------------- Eval24 macro mset # @_Eval_ ~0.5~\,~1~ endm ;------------------------------------------------------------------------------- Eval32 macro mset # @_Eval_ ~0.5~\,~1~ endm ;------------------------------------------------------------------------------- Eval40 macro mset # @_Eval_ ~0.5~\,~1~ endm ;------------------------------------------------------------------------------- Eval48 macro mset # @_Eval_ ~0.5~\,~1~ endm ;------------------------------------------------------------------------------- Eval56 macro mset # @_Eval_ ~0.5~\,~1~ endm ;------------------------------------------------------------------------------- Eval64 macro mset # @_Eval_ ~0.5~\,~1~ endm ;------------------------------------------------------------------------------- Str16 macro [Number],[ResultString] @_DoStr 16\,~1~\,~2~ endm ;------------------------------------------------------------------------------- Str24 macro [Number],[ResultString] @_DoStr 24\,~1~\,~2~ endm ;------------------------------------------------------------------------------- Str32 macro [Number],[ResultString] @_DoStr 32\,~1~\,~2~ endm ;------------------------------------------------------------------------------- Str40 macro [Number],[ResultString] @_DoStr 40\,~1~\,~2~ endm ;------------------------------------------------------------------------------- Str48 macro [Number],[ResultString] @_DoStr 48\,~1~\,~2~ endm ;------------------------------------------------------------------------------- Str56 macro [Number],[ResultString] @_DoStr 56\,~1~\,~2~ endm ;------------------------------------------------------------------------------- Str64 macro [Number],[ResultString] @_DoStr 64\,~1~\,~2~ endm ;------------------------------------------------------------------------------- _?sei_ macro #ifdef _NOCLI_ mexit #endif #ifndef _MTOS_ mexit #endif mset # #ifnb ~','2~ = sp mexit #endif #ifnb ~','2~ = spx mexit #endif #ifnb ~','2~ = psp mexit #endif #ifdef ~1,~ #if ::~1,~ < 2 mexit #endif #endif sei endm ;------------------------------------------------------------------------------- _?cli_ macro #ifdef _NOCLI_ mexit #endif #ifndef _MTOS_ mexit #endif mset # #ifnb ~','2~ = sp mexit #endif #ifnb ~','2~ = spx mexit #endif #ifnb ~','2~ = psp mexit #endif #ifdef ~1,~ #if ::~1,~ < 2 mexit #endif #endif cli endm ;------------------------------------------------------------------------------- _DoLoad macro BitSize[,Variable] ;if no Variable, wherever HX points #if :macronest = 1 #Warning Macro NOT to be called directly #endif mreq 1:BitSize[,Variable] #temp ~1~/8 ;;bytesize now in :temp mdel 1 ;;get rid of bitsize parm mset # ;;unite all parms into one mtrim 1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mset 9 ;;assume signed (when SIGNED) #ifparm ~1.1.1~~1.{:1}~ = [] mset 9,unsigned mset 1,~1.2.{:1-2}~ #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@_not_x_ ~1~ ;;X-mode not allowed ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifnum ~1~ mset 1,#~1~ ;;numerics use immediate mode #endif #ifb ~,1~ #ifdef ~#1~ #ifz ::~#1~ mset 1,#~#1~ ;;named constants use immediate mode #endif #endif #endif #ifnb ~#~ ;;process immediate mode @@Msg Load{:temp*8} ~1~ mset 1,~#1~ mset 0 ;;use as flag for CLRH usage mdo #ifz ~#1~>{:mloop-1*8}&$FF #ifz :text clrh mset 0,clrh ;;flag CLRH was used #endif pshh #else ldx #~#1~>{:mloop-1*8}&$FF pshx #endif mloop :temp mexit #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifnb ~1,~ #ifb ~1.1.1~ = . ;;except for pointers #ifnz ::~1,~ ;;and constants #if ::~1,~ <> :temp ;;different-size variables @@_?sei_ ~1~ @@pushv ~1~ ;;are pushed and then resized @@_?cli_ ~1~ @ResizeTOS #{::~1,~}\,#{:temp}\,\,~9~ mexit #endif #endif #endif #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifndef ~1,~ #Warning Loading forward \@~1,~\@ as var #endif @@Msg Load{:temp*8} ~1~ @@lea ~1~ ;;default case @@_?sei_ ~1~ call StackLoad{:temp*8} ;;load as is @@_?cli_ ~1~ #ifspauto #spadd :temp #endif endm ;------------------------------------------------------------------------------- _DoSave macro BitSize[,Variable] ;if no Variable, wherever HX points #if :macronest = 1 #Warning Macro NOT to be called directly #endif mreq 1:BitSize[,Variable] mset 2,~@@~ mtrim 2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mset 9 ;;assume signed (when SIGNED) #ifparm ~2.1.1~~2.{:1}~ = [] mset 9,unsigned mset 2,~2.2.{:2-2}~ #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@_not_x_ ~2~ #ifnb ~2,~ #ifb ~2.1.1~ = . ;;except for pointers #ifnz ::~2,~ ;;and constants #if ::~2,~ <> ~1~/8 ;;different-size variables @@ResizeTOS #{~1~/8}\,#{::~2,~}\,\,~9~ @@_?sei_ ~2~ @@pullv ~2~ ;;are resized and then pulled @_?cli_ ~2~ mexit #endif #endif #endif #endif @@Msg Save~1~ ~2~ @@lea ~2~ ;;default case @@_?sei_ ~2~ call StackSave~1~ ;;save as is @@_?cli_ ~2~ #ifspauto #spadd -~1~/8 #endif endm ;------------------------------------------------------------------------------- _DoSwap macro BitSize #if :macronest = 1 #Warning Macro NOT to be called directly #endif call StackSwap~1~ endm ;------------------------------------------------------------------------------- _DoOperation macro Operation[,BitSize] #if :macronest = 1 #Warning Macro NOT to be called directly #endif mdef 2,~1.{:1-1}~ @@Msg ~1~ call Stack~1~ #ifspauto #spadd -~2~/8 #endif endm ;------------------------------------------------------------------------------- _DoMath macro Operation,BitSize[,Operand1[,Operand2[,Answer]]] #if :macronest = 1 #Warning Macro NOT to be called directly #endif #ifnoparm ~3~ @_DoOperation ~1~ mexit #endif #ifnoparm ~4~ @@Load~2~ ~3~ #ifnoparm ~1~ = Add~2~ #ifnoparm ~1~ = Mul~2~ ;except for Add and Mul which are commutative, we must swap the stack call StackSwap~2~ ;one parm is Operand2 (eg, Div32 XXX does TOS/XXX) #endif #endif @_DoOperation ~1~ mexit #endif @@Load~2~ ~4~ @@Load~2~ ~3~ @@_DoOperation ~1~ #ifparm ~5~ @Save~2~ ~5~ #endif endm ;------------------------------------------------------------------------------- _DoAbs macro BitSize[,Source][,Destination] #if :macronest = 1 #Warning Macro NOT to be called directly #endif @@Msg Abs~1~ ~@@~ @@_FindStkMth_ ~1~ mset 1,{:mexit} #ifparm ~2~ @@Load~1~ ~2~ #endif call StackAbs~1~ #ifparm ~2~~3~ @Save~1~ ~3~ #endif endm ;------------------------------------------------------------------------------- _DoNeg macro BitSize[,Source][,Destination] #if :macronest = 1 #Warning Macro NOT to be called directly #endif @@Msg Neg~1~ ~@@~ @@_FindStkMth_ ~1~ mset 1,{:mexit} #ifparm ~2~ @@Load~1~ ~2~ #endif call StackNegate~1~ #ifparm ~2~~3~ @Save~1~ ~3~ #endif endm ;------------------------------------------------------------------------------- _DoStr macro BitSize,[Variable],[ResultString] #if :macronest = 1 #Warning Macro NOT to be called directly #endif @@_FindStkMth_ ~1~ #ifb ~2~ #if ~1~ <> :mexit #Warning Size mismatch (Using Str~1~ for MATHSIZE={:mexit}) #endif #endif mset 1,{:mexit} #ifparm ~'~,3~'.{:3}~ = x pshhx #endif #ifparm ~2~ @@Load~1~ ~2~ #ifparm ~'~,3~'.{:3}~ = x ldhx ~1~/8+1,asp ;reload user HX for next LDHX #endif #endif #ifnb ~2~ @@Msg Convert \@~2~\@ ({::~2,~*8}-bit) to ASCIZ in \@~3~\@ #endif @@lea ~3~ call Stack~1~ToASCIZ #ifparm ~2~ ais #~1~/8 #endif #ifparm ~'~,3~'.{:3}~ = x pulhx #endif endm