;******************************************************************************* ;* COMMON EQUATES -- MCU INDEPENDENT -- FOR ASM11 ASSEMBLER ;******************************************************************************* ;* Language : Motorola/Freescale/NXP 68HC11 Assembly Language (aspisys.com/ASM11) ;* Status : FREEWARE Copyright (c) 2020 by Tony Papadimitriou <tonyp@acm.org> ;* Original : http://www.aspisys.com/code/hc11/common.html ;******************************************************************************* ; Dot-ending names (XXX.) indicates a unique bit mask (possibly multiple bits) ; Underscore surrounded names (_XXX_) indicates special system symbols such as ; CCR offsets, etc. ; Constants use uppercase (XXX) ; Variables use lowercase and underscores as needed (my_var). ; Pointers begin with a point/dot (.xxx). ; Code labels use CamelCase ; Local labels end with @@ (although ASM11 allows @@ to be anywhere inside label) ;******************************************************************************* #ifmain ;----------------------------------------------------------------------- #Fatal This file can not be used stand-alone #endif ;------------------------------------------------------------------------ NOT def -1 ;Used with XOR to get NOT result ;******************************************************************************* ; Symbol to the left of macro call (if present) and :MEXIT internal variable ; are SET to the integer Log2 (log base two) of the given expression. ; Quick-n-dirty calculation of integer part of log2(n) for values upto 2^31-1 ; Useful to get power from value (e.g., as when used with various prescalers.) ; With the optional ShiftLeftBits parameter, one can shift the result into the ; expected bit positions (e.g., within a larger bitmap). #ifnomdef Log2 Log2 macro Expr[,ShiftLeftBits] mreq 1:Usage: Label @~0~ Expression[,ShiftLeftBits] mdef 2,0 #temp :loop-2 #ifz ~1~ #temp :temp<{~2~} #ifparm ~label~ ~label~ set :temp #endif mexit :temp #endif mset 1,{~1~>1} mtop endm #endif ;******************************************************************************* ; Restrict the value of a constant label between a minimum and a maximum ; printing a warning if the value is outside the allowed range ConstMinMax macro Symbol[,MinValue][,MaxValue] mreq 1:Symbol[,MinValue][,MaxValue] mset 0,~2~<=~1,~<=~3~ [not {~1,~}] #ifb ~2~~3~ merror No MinValue or MaxValue given #endif #ifnb ~2~ #if ~1,~ < ~2~ #Warning ~text~ #endif #endif #ifnb ~3~ #if ~1,~ > ~3~ #Warning ~text~ #endif #endif endm ;******************************************************************************* ; Restrict the value of a constant label to one of the specified values ; printing a warning if the value is not in the given set ConstValues macro Symbol,Value[,Value]* mreq 1,2:Symbol,Value[,Value]* #ifndef ~1,~ mexit ;;mstop ~1,~ not yet defined #endif mdo 2 #if ~1,~ = ~{:mloop}.~ mexit #endif mloop :n mset 0,~1,~ mdel 1 mset # #Warning ~text~ ({~text~}) not in [~1~] endm ;******************************************************************************* VDD def 5000 ;MCU voltage in mV ;=============================================================================== #ifndef Hz #ifndef KHZ #ifndef MHZ MHZ def 8 ;default for most anything #ifdef __DK68HC11__ HZ def 9830400 #endif #endif #endif #endif ? macro FromHz,ToHz mreq 1,2:FromHz,ToHz #ifdef BUS_~1~ mset 1,BUS_~1~ mset 2,BUS_~2~ #endif #ifdef ~1~ #if ~1~\1000 >= 500 ~2~ set ~1~/1000+1 #else ~2~ set ~1~/1000 #endif #endif #ifparm ~1.1.4~ = BUS_ ~1.5~ set ~1~*4 #endif endm ;------------------------------------------------------------------------------- #ifdef BUS_MHZ BUS_HZ def BUS_MHZ*1000000 BUS_KHZ def BUS_MHZ*1000 #endif @? HZ,KHZ @? KHZ,MHZ MHZ def 8 ;default crystal speed KHZ def MHZ*1000 HZ def KHZ*1000 BUS_HZ def HZ/4 BUS_KHZ def BUS_HZ/1000 BUS_MHZ def BUS_KHZ/1000 MSEC_CYCLES def BUS_KHZ ;number of cycles per millisecond ;------------------------------------------------------------------------------- ? macro #temp :index-1 Bit{:temp}. equ 1<{:temp} mtop 16 endm @? ;Define Bit0 .. Bit15 ;------------------------------------------------------------------------------- ; ISR (zero-based) offsets account for the return address of OS11 dispatcher's JSR ;------------------------------------------------------------------------------- _DATA_ equ 0 ;start of stacked data, if any _CCR_ next _DATA_,1 _B_ next _DATA_,1 _A_ next _DATA_,1 _X_ next _DATA_,2 _Y_ next _DATA_,2 _PC_ next _DATA_,2 _D_ equ _B_,2 ;This is for loading D reversed ;Alternative (old style) names DATA_ equ _DATA_ ;start of stacked data, if any PC_ equ _PC_,2 Y_ equ _Y_,2 X_ equ _X_,2 A_ equ _A_,1 B_ equ _B_,1 D_ equ _D_,2 ;This is for loading D reversed CCR_ equ _CCR_,1 ;------------------------------------------------------------------------------- ; CCR bits (masks) ;------------------------------------------------------------------------------- S. equ %10000000 ;Stop inhibit X. equ %01000000 ;XIRQ disable H. equ %00100000 ;Half Carry I. equ %00010000 ;IRQ disable N. equ %00001000 ;Negative Z. equ %00000100 ;Zero V. equ %00000010 ;Overflow C. equ %00000001 ;Carry ; BPROT Bits PTCON. equ Bit4. ;Protect CONFIG programming @bits BPRT,0,3 ; CONFIG Bits NOSEC. equ Bit3. ;NOSEC (no security option) NOCOP. equ Bit2. ;NOCOP in CONFIG register ROMON. equ Bit1. ;ROM is ON/enabled EEON. equ Bit0. ;EEPROM is ON/enabled ; OPTION Bits ADPU. equ %10000000 ;A/D Power-Up CSEL. equ %01000000 ;Charge Pump Clock Select IRQE. equ %00100000 ;IRQ Select Edge Sensitive Only DLY. equ %00010000 ;Delay out of STOP mode CME. equ %00001000 ;Clock Monitor Enable @bits CR,0,1 ;COP Timer Rate Select ; SCI Bits TIE. equ %10000000 ;SCI Transmitter Interrupt Enable TCIE. equ %01000000 ;SCI Transmit Complete Interrupt Enable RIE. equ %00100000 ;SCI Receiver Interrupt Enable ILIE. equ %00010000 ;SCI Idle-Line Interrupt Enable TE. equ %00001000 ;SCI Transmitter Enable RE. equ %00000100 ;SCI Receiver Enable RWU. equ %00000010 ;SCI Receiver Wakeup Control SBK. equ %00000001 ;SCI Send Break TDRE. equ %10000000 ;SCI Transmit Register Empty TC. equ %01000000 ;SCI Transmit Complete Flag RDRF. equ %00100000 ;SCI Receive Register Full IDLE. equ %00010000 ;SCI Idle Line Detected OR. equ %00001000 ;SCI Overrun Error NF. equ %00000100 ;SCI Noise Error FE. equ %00000010 ;SCI Framing Error ; SPI Bits SPIE. equ %10000000 ;SPI Interrupt Enable SPE. equ %01000000 ;SPI Enable DWOM. equ %00100000 ;PortD OR Wired Mode MSTR. equ %00010000 ;Master Mode Select CPOL. equ %00001000 ;Clock Polarity CPHA. equ %00000100 ;Clock Phase @bits SRP,0,1 ;SPI Clock Rate Select SPIF. equ %10000000 ;SPI Transfer Complete Flag WCOL. equ %01000000 ;Write Collision MODF. equ %00010000 ;Mode Fault ; SPI Pins MISO. equ Bit2. ;Port D pins for manual SPI MOSI. equ Bit3. SCK. equ Bit4. SS. equ Bit5. #ifdef PORTD SPI_MISO @pin PORTD,2 SPI_MOSI @pin PORTD,3 SPI_CLK @pin PORTD,4 SPI_SS @pin PORTD,5 #endif ; ADCTL (A/D Control/Status) Bits CCF. equ %10000000 ;Conversions Complete Flag SCAN. equ %00100000 ;Continuous Scan Control MULT. equ %00010000 ;Multiple/Single Channel Control CD. equ %00001000 ;Channel Select D CC. equ %00000100 ;Channel Select C CB. equ %00000010 ;Channel Select B CA. equ %00000001 ;Channel Select A ; PACTL (Pulse Accumulator Control) Bits DDRA7. equ %10000000 ;Data Directive for PortA[7] PAEN. equ %01000000 ;Pulse Accumulator System Enable PAMOD. equ %00100000 ;Pulse Accumulator Mode PEDGE. equ %00010000 ;Pulse Accumulator Edge Control DDRA3. equ %00001000 ;Data Directive for PortA[3] I4O5. equ %00000100 ;IC4/OC5 select @bits RTR,0,1 ;RTI Rate Select ; Timer Bits TOF. equ %10000000 RTIF. equ %01000000 PAOVF. equ %00100000 PAIF. equ %00010000 ; PIOC (Parallel IO Control) Bits STAF. equ %10000000 ;STRA Interrupt Status Flag STAI. equ %01000000 ;STRA Interrupt Enable Mask CWOM. equ %00100000 ;Port C Wired-OR Mode HNDS. equ %00010000 ;Handshake Mode OIN. equ %00001000 ;Output or Input Handshake Select PLS. equ %00000100 ;Pulse/Interlocked Handshake Operation EGA. equ %00000010 ;Active Edge for STRA INVB. equ %00000001 ;Invert STRB ;Vectors by name Vsci def $FFD6 Vspi def $FFD8 Vpai def $FFDA Vpao def $FFDC Vrto def $FFDE Vtic4 def $FFE0 Vtoc5 def Vtic4 ;alias for Vtic4 Vtoc4 def $FFE2 Vtoc3 def $FFE4 Vtoc2 def $FFE6 Vtoc1 def $FFE8 Vtic3 def $FFEA Vtic2 def $FFEC Vtic1 def $FFEE Vrti def $FFF0 Virq def $FFF2 Vxirq def $FFF4 Vswi def $FFF6 Villop def $FFF8 Vcop def $FFFA Vcmf def $FFFC Vreset def $FFFE ;Miscellaneous BYTE equ 1 ;8-bit quantity WORD equ 2 ;16-bit quantity DWORD equ 4 ;32-bit quantity QWORD equ 8 ;64-bit quantity ERASED_STATE def $FFFF ;[E]EPROM Erased State JMP_OPCODE equ $7E ;JMP extended opcode #ifdef DEBUG BPS_RATE def 125 ;for SIM11x debugging, use maximum speed #endif BPS_RATE def 96 ;9600 bps for the SCI ;******************************************************************************* ; Displays an error message if the assembly-time condition is false ; (The condition should be written as to be compatible with the #IF directive) assert macro Condition[,message] mset #',' #if ~1~ mexit #endif mdel 1 ;;get rid of condition mset # ;;unify string message mdef 1,Assertion failed (~1~) ;;default message merror ~1~ endm ;******************************************************************************* ; Macro(s) SetChipSelects macro [[#]STACKTOP] ;to be called first thing after reset #ifdef XRAM_END mdef 1,#XRAM_END #else mdef 1,#STACKTOP #endif #temp {RAM>8&$F0}|{REGS>12} #ifz :temp clr XINIT #else lda #:temp sta XINIT ;Set register base #endif #ifdef __ASPISYS__ #if MHZ <= 16 clr CSSTRH ;No clock stretch #else #Message 1 clock stretch for external EEPROM lda #1 ;EEPROM 1 clock stretch sta CSSTRH ;@>16MHz crystal (>4MHz bus) #endif clr CSGADR ;RAM at $0000 lda #%1 ;32K RAM sta CSGSIZ lda #%01000101 ;CSIO1 Active High, 32K ROM at $8000 sta CSCTL #endif lds ~1~ endm ;******************************************************************************* ; Macro to dynamically execute another macro or instruction as one atomic ; operation (i.e., with interrupts temporarily disabled). ; When done with the operation, it restores interrupts to their original status. ; You could use with any macro. For example, using an ADD.L (add longs) macro ; you could perform the addition with interrupts disabled, even if the original ; macro does not provide for atomicity of operation(s). Example: ; @atomic add.l,Number1,Number2,Answer Atomic macro [@]CmdToDo[,Parameter]* mreq 1:[@]CmdToDo[,Parameter]* #ifparm ~1.1.1~ = @ mset 1,@~1~ ;;make macro a @@ call #endif mswap 0,1 mdel 1 mset # pshcc sei ~text~ ~1~ pulcc endm ;******************************************************************************* ; Find a character in the string pointed to by X, and point right past it ; The user's original RegA is not destroyed SkipChar macro [[#]Character] mset # #ifnb ~1~ psha @@_lda_ ~1~ #endif Loop$$$ tst ,x ;;is it end of ASCIZ string? beq Done$$$ cmpa ,x beq Done$$$ ;;char found, done inx bra Loop$$$ ;;repeat until end of ASCIZ string Done$$$ inx #ifnb ~1~ pula #endif endm ;******************************************************************************* ; Skip over the current and following characters as long as they match the target ; On completion, X -> first non-target character ; The user's original RegA is not destroyed EatChar macro [[#]Character] mset # #ifnb ~1~ psha @@_lda_ ~1~ #endif Loop$$$ cmpa ,x ;;compare first char bne Done$$$ ;;if not same, CBEQ won't work inx bra Loop$$$ Done$$$ #ifnb ~1~ pula #endif endm ;******************************************************************************* ; Find (in RegA) the minimum between RegA and operand MinA macro Operand mset # mreq 1:Operand cmpa ~1~ bls Done$$$ lda ~1~ Done$$$ endm ;******************************************************************************* ; Find (in RegA) the maximum between RegA and operand MaxA macro Operand mset # mreq 1:Operand cmpa ~1~ bhs Done$$$ lda ~1~ Done$$$ endm ;******************************************************************************* ; Point X to a TableEntry given its zero-based index, table address, and ; TableEntry bytesize. Index is optional (in case it is already loaded in RegA) TblOfs macro [[#]Index],[#]Table,[#]TableEntrySize mreq 2,3:[[#]Index],[#]Table,[#]TableEntrySize @@_not_x_ ~2~ pshd @@_lda_ ~1~ ;A = index #temp #ifparm ~3.1.1~ = # ;;special case optimization #!if ~#3~ = 1 ;;for defined immediate of size 1 #temp 1 ;mark action taken #endif #ifnum ~#3~ ;;for numeric immediate #if ~#3~ = 1 ;;of size 1 #temp 1 ;mark action taken #endif #endif #endif #ifz :temp ldb ~3~ ;B = bytesize of TableEntry mul ;D = offset into table #else tab clra ;D = offset into table #endif addd ~2~ xgdx ;X -> TableEntry puld endm ;******************************************************************************* ; Macro to use XRAM if XRAM has been defined, RAM otherwise XRAM macro #RAM #ifdef XRAM #XRAM #endif endm ;******************************************************************************* ; EQU but it also copies the size of the original label ; (a single label is expected as parameter, no expressions) equ macro Label mset # mreq 1:Label @~0~ Label mset 0,Label expected, found #ifnum ~1~ mstop ~text~ number (~1~) #endif #ifstr ~1~ mstop ~text~ string (~1~) #endif #ifnb ~'()[]+-*/\,<>^&|'2~ mstop ~text~ expr (~1~) #endif ~label~ set ~1~,::~1~ endm ;******************************************************************************* ; Macro to allocate a variable to #RAM or #XRAM (if XRAM defined) based on size ; [Smaller variables (upto LONG size) go into #RAM, everything else into #XRAM] Var macro Size[,MaxSizeForRAM] #ifnb ~2~ mset 0,~2~ ;;set new MaxSizeForRAM default #ifb ~1~ mexit ;;special case only to define MaxSizeForRAM #endif #endif mdef 0,4 ;;startup MaxSizeForRAM default #push #RAM #ifdef XRAM ;;when XRAM is defined #if ~#1~ > ~text~ ;;anything above ~TEXT~ goes to XRAM #XRAM #endif #if :RAM+~#1~ > RAM_END ;;if RAM is full or not enough, use XRAM #XRAM #endif #endif ~label~ set *,~1~ rmb ~1~ #pull endm ;******************************************************************************* ; Repeat a number of instructions a constant number of times ; Example: @rep 2,lsla,rolx ;shift left XA twice Rep macro Times,Instruction1[,Instruction2]* mreq 1,2:Times,Instruction1[,Instruction2]* #ifz ~1~ mexit ;;nothing to do #endif mdo 2 #ifparm ~{:mloop}.1.2~ = @@ ;;convert @@macro to @macro mset :mloop,~{:mloop}.2~ #endif #ifparm ~{:mloop}.1.1~ = @ ;;convert @macro to @@macro mset :mloop,@~{:mloop}.~ #endif ~{:mloop}.~ mloop :n mtop ~1~ endm ;******************************************************************************* ; Checks the passed parameter and issues an error if it is X-indexed ; (This is meant to be called from other macros -- not to be called directly) _not_x_ macro mset # #ifb ~1~ mexit ;;nothing to do #endif #ifparm ~'~,1~'.{:1}~ = x mstop X-index not allowed (~1~) #endif endm ;******************************************************************************* ; Checks the passed parameter and issues an error if it is Y-indexed ; (This is meant to be called from other macros -- not to be called directly) _not_y_ macro mset # #ifb ~1~ mexit ;;nothing to do #endif #ifparm ~'~,1~'.{:1}~ = y mstop Y-index not allowed (~1~) #endif endm ;******************************************************************************* ; Checks the passed parameter and issues an error if it is immediate mode ; (This is meant to be called from other macros -- not to be called directly) _not_#_ macro #ifb ~1~ mexit ;;nothing to do #endif #ifparm ~#~ mstop Immediate mode not allowed (~1~) #endif endm ;******************************************************************************* ; Checks the passed parameter and issues an error if it is NOT immediate mode ; (This is meant to be called from other macros -- not to be called directly) _#_ macro #ifb ~1~ mexit ;;nothing to do #endif #ifb ~#~ mstop Immediate mode expected (~1~) #endif endm ;******************************************************************************* ; Check if no size info exists for give symbol (parameter) _nosize_ macro mset # mset 0,mstop [~00~] No size (~1~) #ifnb ~#~ ~text~ [immediate] #endif #ifb ~1,~ ~text~ [blank] #endif #ifnum ~1,~ ~text~ [numeric] #endif #ifndef ~1,~ ~text~ [undefined] #endif #ifz ::~1,~ ~text~ [constant] #endif endm ;******************************************************************************* ; Check if all given non-immediate mode operands have the same size ; (Skip immediate mode ones, and constants -- labels with size zero) ; (This is meant to be called from other macros -- not to be called directly) _samesize_ macro Operand1,Operand2[,Operand]* mreq 1,2:Operand1,Operand2[,Operand]* mset 0 mdo mswap 1,{:mloop} #ifb ~#~ #ifnb ~1,~ @@_nosize_ ~1~ #ifb ~text~ mset 0,~1~ #endif #if ::~text,~ <> ::~1,~ mstop \@~text~\@ ({::~text,~}) size <> \@~1~\@ ({::~1,~}) #endif #endif #endif mloop :n endm ;******************************************************************************* ; Check if size exists, and optionally if it is one of the expected ones ; (This is meant to be called from other macros -- not to be called directly) _size_ macro Label[,ExpectedSize]* @@_nosize_ ~1~ mdo 2 #ifnb ~{:mloop}.~ #if ::~1,~ = ~{:mloop}.~ mexit #endif #endif mloop :n mswap 0,1 mdel 1 mset # mstop \@~text,~\@ size {::~text,~} not in (~1~) endm ;******************************************************************************* ; Optional LDA: Do a LDA instruction but only if the parameter is non-blank ; (This is meant to be called from other macros -- not to be called directly) _lda_ macro mset # #ifb ~1~ mexit #endif #ifparm ~#~ #!ifz ~#1~ clra mexit #endif #endif lda ~1~ endm ;******************************************************************************* ; Optional STA: Do a STA instruction but only if the parameter is non-blank ; (This is meant to be called from other macros -- not to be called directly) _sta_ macro #ifnb ~@~ sta ~@~ #endif endm ;******************************************************************************* ; LDA & CMP combo but it optimizes LDA to CLRA and eliminates CMP if the ; corresponding effective value is #0 ; (This is meant to be called from other macros, but it may be called directly) _ldacmp_ macro [#]Operand1,[#]Operand2 #ifparm ~#~ #ifdef ~#1~ mset 1,~#~{~#1~} #endif #endif #ifparm ~1~ = #0 clra #else lda ~1~ #endif mswap 1,2 #ifparm ~#~ #ifdef ~#1~ mset 1,~#~{~#1~} #endif #endif cmpa ~1~ ;;needed even when #0 to adjust Carry endm ;******************************************************************************* ; Swap two byte-size variables (does not protect RegA) - Primitive macro ; (This is meant to be called from other macros, but it may be called directly) _swap_ macro Variable1,Variable2 lda ~1~ psha lda ~2~ sta ~1~ pula sta ~2~ endm ;******************************************************************************* ; Swap two same-size variables swap.s macro Variable1,Variable2 mreq 1,2:Variable1,Variable2 @@_samesize_ ~@~ psha mdo @@_swap_, ~1,~+{:mloop-1}~,1~ ~2,~+{:mloop-1}~,2~ mloop ::~1,~ pula endm ;******************************************************************************* ; Get A from the location pointed to by the parm, while bumping up that pointer GetNextA macro Pointer mreq 1:Pointer #ifparm ~#~ mstop Pointer (~1~) must be a word variable #endif @@_not_x_ ~@~ ldx ~@~ lda ,x inx stx ~@~ endm ;******************************************************************************* ; Put A into the location pointed to by the parm, while bumping up that pointer PutNextA macro Pointer mreq 1:Pointer #ifparm ~#~ mstop Pointer (~1~) must be a word variable #endif @@_not_x_ ~@~ ldx ~@~ sta ,x inx stx ~@~ endm ;******************************************************************************* ; Load Effective Address in RegX lea macro mset # #ifb ~1~ mexit ;;no parm, nothing to do #endif #ifparm ~#~ ldx ~1~ ;;immediate value load as is mexit #endif #ifparm ~1.1.1~ = . ;;dot-beginning symbols treat as pointers ldx ~1~ mexit #endif #ifparm ~1.1.2~ = ?. ;;dot-beginning file-local symbols treat as pointers ldx ~1~ mexit #endif #ifparm ~,1~ ;;indexed modes #ifparm ~,1~ = ,x #ifnb ~1,~ @aix #~1,~ ;;X-indexed add possible offset #endif mexit #endif ldx ~1~ ;;any other index treat as pointer (regardless of name convention) mexit #endif ldx #~1~ ;;everything else is fixed RAM endm ;******************************************************************************* ; Find the Greatest Common Divisor (GCD) of two constants. ; Answer is placed in LABEL (if present) and :MEXIT variable gcd macro a,b #ifz ~1~ mexit 1 #endif #ifz ~2~ mexit 1 #endif #if ~1~ = ~2~ #ifparm ~label~ ~label~ set ~1~ #endif mexit ~1~ #endif #if ~1~ > ~2~ mset 1,{~1~-{~2~}} mtop #endif mset 2,{~2~-{~1~}} mtop endm ;******************************************************************************* ; Find the Least Common Multiple (LCM) of two constants. Prerequisite macro: GCD ; Note: To avoid overflow, first divides, then multiplies. GCD certainly divides ; both numbers, so no problem doing so, and it's more efficient. ; Answer is placed in LABEL (if present) and :MEXIT variable lcm macro a,b @@gcd ~@~ #ifparm ~label~ ~label~ set {~1~}/:mexit*{~2~} #endif mexit {~1~}/:mexit*{~2~} endm ;******************************************************************************* ; Allows easy marking of any incomplete sections of code to be looked after at ; a later time (usually, during development) ; Define the symbol '...' to have errors display for each use of the macro ... macro Optional message #ifdef ... mset # #ifb ~1~ mset 1,\@~procname~\@ is incomplete #else mset 1,\@~procname~\@: ~1~ #endif #Hint ~1~ mexit #endif nop ;;avoids branch warnings #Memory *-1 ;;and removes possible warning endm ;******************************************************************************* ; Vector assignment ; (Places vector in #VECTORS segment, then returns to current segment) Vector macro Vvector,ISR_Address #ifb ~2~ #ifndef ~1~ mexit ;avoids error on empty but undefined vectors #endif #endif mdef 2,AnRTI #push #VECTORS #ppc org ~1~ dw ~2~ org :ppc #pull endm ;******************************************************************************* ; PUSH any variable onto the stack. If size is missing, size one is assumed. ; (All registers are destroyed) ;******************************************************************************* ; PUSH any variable onto the stack. If size is missing, size one is assumed. ; Constants require a size as it cannot be determined automatically. ; (All registers may be destroyed) PushV macro Variable[ SizeOf(Variable)] mset #' ' mreq 1:Variable[ SizeOf(Variable)] #ifnb ~#~ ;;immediate mode mreq 1,2:Constant SizeOf(Constant) #if ~2~ < 0 merror Negative size: ~2~ #endif mdo lda ~1~>{:mloop-1*8}&$FF psha mloop ~2~ #ifnz ~#1~>{:mloop*8} merror Constant ~#1~ bigger than ~2~ byte(s) #endif mexit #endif #ifnb ~1,~ #ifnz ::~1,~ mdef 2,{::~1,~} #endif #endif mdef 2,1 #if ~2~ < 0 merror Negative size: ~2~ #endif #Message ~0~ ~1~ ({~2~*8}-bit) #if ~2~ = 1 ;;single-byte variable case #ifb ~1.1.1~ = . ;;but not for pointers lda ~1~ psha mexit #endif #endif mdo lda ~1,~+{~2~-:mloop},x psha mloop ~2~ endm ;******************************************************************************* ; PULL any variable from the stack. If size is missing, size one is assumed. ; (All registers may be destroyed) PullV macro Variable[ SizeOf(Variable)] mset #' ' mreq 1:Variable[ SizeOf(Variable)] @@_not_#_ ~1~ #ifnz ::~1,~ mdef 2,{::~1,~} #endif mdef 2,1 #if ~2~ < 0 merror Negative size: ~2~ #endif #Message ~0~ ~1~ ({~2~*8}-bit) #if ~2~ = 1 ;;single-byte variable case #ifb ~1.1.1~ = . ;;but not for pointers pula sta ~1~ mexit #endif #endif mdo pula sta ~1,~+{:mloop-1},x mloop ~2~ endm ;******************************************************************************* ; A group of macros for use with any sized variable ;******************************************************************************* ;******************************************************************************* ; Clear any sized variable ClrVar macro Variable mset # mreq 1 @@_nosize_ ~1~ #ifb ~,1~ mset 1,~#1~ #if ::~1,~ < 256 #ifz ]{~1~-1} pshx ldx #::~1~ Loop$$$ clr ~1~-1,x dex bne Loop$$$ pulx mexit #endif pshx psha clra ldx #::~1~ Loop$$$ sta ~1~-1,x dex bne Loop$$$ pula pulx mexit #endif #endif #if ::~1,~ <= 8 #ifnb ~,1~ @clr.s ~1~ mexit #endif #endif pshx psha lda #::~1,~ ldx ~1~ Loop$$$ clr ,x inx deca bne Loop$$$ pula pulx endm ;******************************************************************************* ; Test for zero for any sized variable zero?.s macro Variable mset # mreq 1 @@_nosize_ ~1~ mdo #if :mloop = 1 lda ~1,~+{:mloop-1}~,1~ #else ora ~1,~+{:mloop-1}~,1~ #endif mloop ::~1,~ endm ;******************************************************************************* ; CLR for any sized variable clr.s macro Variable mset # mreq 1 @@_nosize_ ~1~ #ifb ~,1~ #ifnz ]~1~ psha clra mdo sta ~1,~+{:mloop-1}~,1~ mloop {::~1,~} pula mexit #endif #endif mdo clr ~1,~+{:mloop-1}~,1~ mloop ::~1,~ endm ;******************************************************************************* ; INC for any sized variable inc.s macro Variable mset # mreq 1 @@_nosize_ ~1~ mdo inc ~1,~+{::~1,~-:mloop}~,1~ #if :mloop <> ::~1,~ bne Done$$$ #endif mloop ::~1,~ Done$$$ endm ;******************************************************************************* ; DEC (simulation) for any sized variable. dec.s macro Variable mset # mreq 1 @@_nosize_ ~1~ psha @@sub.s, ~1~ #1 ~1~ @@cmp.s, ~1~ #0 pula endm ;******************************************************************************* ; COM for any sized variable com.s macro Variable mset # mreq 1 @@_nosize_ ~1~ #ifb ~,1~ #ifnz ]~1~ psha mdo lda ~1,~+{:mloop-1}~,1~ coma sta ~1,~+{:mloop-1}~,1~ mloop {::~1,~} pula mexit #endif #endif mdo com ~1,~+{:mloop-1}~,1~ mloop ::~1,~ endm ;******************************************************************************* ; ABS for any sized variable abs.s macro Variable mset # mreq 1:Variable @@tst.b ~1~ bpl Done$$$ @@neg.s ~1~ Done$$$ endm ;******************************************************************************* ; NEG for any sized variable neg.s macro Variable mset # mreq 1 @@_nosize_ ~1~ #if ::~1,~ > 1 mdo com ~1,~+{:mloop-1}~,1~ mloop ::~1,~-1 #endif neg ~1,~+{::~1,~-1}~,1~ #if ::~1,~ > 1 mdo bne Done$$$ inc ~1,~+{::~1,~-:mloop-1}~,1~ mloop ::~1,~-1 Done$$$ #endif endm ;******************************************************************************* ; MOV for any sized variable (simpler version that does not test MSB) move.s macro [#]Source,Destination @copy.s ~@~ endm ;******************************************************************************* ; MOV for any sized variable (but also tests MSB for negative) mov.s macro [#]Source,Destination @@move.s ~@~ #ifnb ~2~ = x+ #if ::~1,~ < 2 mexit ;;single byte var, no need for TST #endif tst ~1~ ;;var,x+ case mexit #endif #if ::~2,~ < 2 mexit ;;single byte var, no need for TST #endif tst ~2~ ;;all other cases endm ;******************************************************************************* ; MOVA for any sized variable mova.s macro [#]Source,Destination mreq 1,2:Source,Destination #ifb ~#~ @@_samesize_ ~@~ #else @@_nosize_ ~2~ #endif mset 0 ;;no CLRA used mdo #ifnb ~#~ #temp ;;no optimization #ifdef ~#1~ #ifz ~#1~>{::~2,~-:mloop*8}&$FF #ifb ~text~ clra #endif mset 0,clra ;;CLRA used #temp 1 ;;optimization #endif #endif #ifz :temp ;;if no optimization lda ~1~>{::~2,~-:mloop*8}&$FF mset 0 ;;no CLRA used #endif #else lda ~1,~+{:mloop-1}~,1~ #endif sta ~2,~+{:mloop-1}~,2~ mloop ::~2,~ endm ;******************************************************************************* ; Copy for any sized variable copy.s macro psha @@mova.s ~@~ pula endm ;******************************************************************************* ; LSL for any sized variable lsl.s macro Variable mset # mreq 1 @@_nosize_ ~1~ mdo #if :mloop = 1 lsl ~1,~+{::~1,~-:mloop}~,1~ #else rol ~1,~+{::~1,~-:mloop}~,1~ #endif mloop ::~1,~ endm ;******************************************************************************* ; LSR for any sized variable lsr.s macro Variable mset # mreq 1 @@_nosize_ ~1~ mdo #if :mloop = 1 lsr ~1,~+{:mloop-1}~,1~ #else ror ~1,~+{:mloop-1}~,1~ #endif mloop ::~1,~ endm ;******************************************************************************* ; ASR for any sized variable asr.s macro Variable mset # mreq 1 @@_nosize_ ~1~ mdo #if :mloop = 1 asr ~1,~+{:mloop-1}~,1~ #else ror ~1,~+{:mloop-1}~,1~ #endif mloop ::~1,~ endm ;******************************************************************************* ; ROR for any sized variable ror.s macro Variable mset # mreq 1 @@_nosize_ ~1~ mdo ror ~1,~+{:mloop-1}~,1~ mloop ::~1,~ endm ;******************************************************************************* ; ROL for any sized variable rol.s macro Variable mset # mreq 1 @@_nosize_ ~1~ mdo rol ~1,~+{::~1,~-:mloop}~,1~ mloop ::~1,~ endm ;******************************************************************************* ; ADD bytes ; Note: No destination required if you only need to add in RegA add.b macro [#]Operand1,[#]Operand2[,Destination] #ifparm ~#~ #ifdef ~#1~ mset 1,~#~{~#1~} #endif #endif mswap 1,2 #ifparm ~#~ #ifdef ~#1~ mset 1,~#~{~#1~} #endif #endif mswap 1,2 #ifparm ~1~~2~ = #0#0 clra @_sta_ ~3~ mexit #endif #ifparm ~1~ = #0 lda ~2~ @_sta_ ~3~ mexit #endif #ifparm ~2~ = #0 lda ~1~ @_sta_ ~3~ mexit #endif lda ~1~ add ~2~ @_sta_ ~3~ endm ;******************************************************************************* ; ADD bytes with Carry ; Note: No destination required if you only interested in the Carry flag adc.b macro [#]Operand1,[#]Operand2[,Destination] #ifparm ~#~ #ifdef ~#1~ mset 1,~#~{~#1~} #endif #endif mswap 1,2 #ifparm ~#~ #ifdef ~#1~ mset 1,~#~{~#1~} #endif #endif mswap 1,2 #ifparm ~1~ = #0 clra adc ~2~ @_sta_ ~3~ mexit #endif #ifparm ~2~ = #0 clra adc ~1~ @_sta_ ~3~ mexit #endif lda ~1~ adc ~2~ @_sta_ ~3~ endm ;******************************************************************************* ; ADD for any sized variable add.s macro [#]Operand1,[#]Operand2,Destination mreq 1,2,3:[#]Operand1,[#]Operand2,Destination @@_samesize_ ~@~ mset 0,@@add.b, ;;first time, do an ADD mdo #ifparm ~#~ mset 0,~text~ ~1~>{:mloop-1*8}&$FF #else mset 0,~text~ ~1,~+{::~3,~-:mloop}~,1~ #endif #ifparm ~2.1.1~ = # mset 0,~text~ ~2~>{:mloop-1*8}&$FF #else mset 0,~text~ ~2,~+{::~3,~-:mloop}~,2~ #endif mset 0,~text~ ~3,~+{::~3,~-:mloop}~,3~ ~text~ mset 0,@@adc.b, ;;next time(s), do an ADC mloop ::~3,~ endm ;******************************************************************************* ; SUB for any sized variable sub.s macro [#]Operand1,[#]Operand2,Destination mreq 1,2:[#]Operand1,[#]Operand2,Destination @@_samesize_ ~@~ #temp #ifb ~3~ @@_nosize_ ~1~ #temp ::~1,~ #else @@_nosize_ ~3~ #temp ::~3,~ #endif mset 0,suba ;;first time, do a SUBA mdo #ifparm ~#~ lda ~1~>{:mloop-1*8}&$FF #else lda ~1,~+{:temp-:mloop}~,1~ #endif #ifparm ~2.1.1~ = # ~text~ ~2~>{:mloop-1*8}&$FF #else ~text~ ~2,~+{:temp-:mloop}~,2~ #endif #ifnb ~3~ sta ~3,~+{:temp-:mloop}~,3~ #endif mset 0,sbca ;;next time(s), do a SBCA mloop :temp endm ;******************************************************************************* ; AND for any sized variable and.s macro [#]Operand1,[#]Operand2,Destination mreq 1,2,3:[#]Operand1,[#]Operand2,Destination @@_samesize_ ~@~ mdo #ifnb ~#~ @@_lda_ ~1~>{::~3,~-:mloop*8}&$FF #else lda ~1,~+{:mloop-1}~,1~ #endif #ifnb ~2.1.1~ = # and ~2~>{::~3,~-:mloop*8}&$FF #else and ~2,~+{:mloop-1}~,2~ #endif sta ~3,~+{:mloop-1}~,3~ mloop ::~3,~ endm ;******************************************************************************* ; OR for any sized variable ora.s macro [#]Operand1,[#]Operand2,Destination mreq 1,2,3:[#]Operand1,[#]Operand2,Destination @@_samesize_ ~@~ mdo #ifnb ~#~ @@_lda_ ~1~>{::~3,~-:mloop*8}&$FF #else lda ~1,~+{:mloop-1}~,1~ #endif #ifnb ~2.1.1~ = # ora ~2~>{::~3,~-:mloop*8}&$FF #else ora ~2,~+{:mloop-1}~,2~ #endif sta ~3,~+{:mloop-1}~,3~ mloop ::~3,~ endm ;******************************************************************************* ; XOR for any sized variable eor.s macro [#]Operand1,[#]Operand2,Destination mreq 1,2,3:[#]Operand1,[#]Operand2,Destination @@_samesize_ ~@~ mdo #ifnb ~#~ @@_lda_ ~1~>{::~3,~-:mloop*8}&$FF #else lda ~1,~+{:mloop-1}~,1~ #endif #ifnb ~2.1.1~ = # eor ~2~>{::~3,~-:mloop*8}&$FF #else eor ~2,~+{:mloop-1}~,2~ #endif sta ~3,~+{:mloop-1}~,3~ mloop ::~3,~ endm ;******************************************************************************* ; CMP for any sized variable, without saving RegA _cmp_.s macro [#]Operand1,[#]Operand2 mreq 1,2:[#]Operand1,[#]Operand2 @@_samesize_ ~@~ #ifparm ~1.1.1~~2.1.1~ = ## mset # mstop Both operands are immediate! \@~1~\@ #endif #temp 1 #ifb ~#~ #temp ::~1,~ #endif #ifb ~2.1.1~ = # #temp ::~2,~ #endif mdo #ifnb ~#~ @@_lda_ ~1~>{:temp-:mloop*8}&$FF #else lda ~1,~+{:mloop-1}~,1~ #endif #ifnb ~2.1.1~ = # cmpa ~2~>{:temp-:mloop*8}&$FF ;;needed even if #0 to adjust Carry #else cmpa ~2,~+{:mloop-1}~,2~ #endif #if :mloop <> :temp bne Done$$$ #endif mloop :temp Done$$$ endm ;******************************************************************************* ; CMP for any sized variable cmp.s macro [#]Operand1,[#]Operand2 psha @@_cmp_.s ~@~ pula endm ;******************************************************************************* ; DIV for any sized variable (HX assumed already set with appropriate values) div.s macro Variable mstop Needs porting to HC11 from 9S08 mset # mreq 1 @@_not_x_ ~1~ @@_nosize_ ~1~ #temp 1 mdo {:temp} lda ~1,~+{:mloop-1}~,1~ idiv sta ~1,~+{:mloop-1}~,1~ mloop ::~1,~ endm ;******************************************************************************* ; A general-purpose FOR loop wrapper ; Limits : Start, Stop and Step (if not immediate) have to match size of ; : ControlVar (or you will get an error) ; Note(s): Use FORS for signed version ; : Negative steps not allowed (will be treated as positive) ; Example: FOR i 1 5 ... MRESUME (where i is any variable declared earlier) fors macro ControlVar [#]Start [#]Stop[ [#]PositiveStep] mset # @for ~1~ endm ;------------------------------------------------------------------------------- for macro ControlVar [#]Start [#]Stop[ [#]PositiveStep] mset #' ' mreq 1,2,3:ControlVar [#]Start [#]Stop[ [#]PositiveStep] mdef 4,#1 ;;default step is one @@_nosize_ ~1~ ;;need sized control variable #temp ::~1,~ mdo 2 #ifnum ~{:mloop}.~ mset :mloop,#~{:mloop}.~ #endif mloop 4 @@_samesize_ ~@~ @@copy.s, ~2~ ~1~ Loop$$$ @@cmp.s, ~1~ ~3~ #ifparm ~00~ = fors !jgt Done$$$ ;;signed version (FORS) #else !jhi Done$$$ ;;unsigned version (FOR) #endif msuspend psha @@add.s, ~1~ ~4~ ~1~ pula !jmp Loop$$$ Done$$$ endm ;******************************************************************************* ; Math-related _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 ;------------------------------------------------------------------------------- _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 mset # mtrim 1 @@_StkMthMax_ ~1~ #temp :mexit @@_FindStkMth_ {:temp} #temp :mexit @@Eval{:temp} ~1~ 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 ;------------------------------------------------------------------------------- _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~ mdef 1,32 mswap 0,1 ;;bitsize now in ~ text ~ mdel 1 mset # #Message -------------------------------------------------- #Message Expr: ~1~ #Message -------------------------------------------------- @@_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 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~ = + #Message Add~text,~ !jsr StackAdd~text,~ ; #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = - #Message Sub~text,~ !jsr StackSub~text,~ ; #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = | #Message Or~text,~ !jsr StackOr~text,~ ; #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = ^ #Message Xor~text,~ !jsr 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~ = * #Message Mul~text,~ !jsr StackMul~text,~ ; #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = / #Message Div~text,~ !jsr StackDiv~text,~ ; #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = \ #Message Mod~text,~ !jsr StackMod~text,~ ; #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = & #Message And~text,~ !jsr StackAnd~text,~ ; #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = > #Message Shr~text,~ !jsr StackShr~text,~ ; #spadd -{~text,~/8} #endif #ifparm ~{:mloop}.1.1~ = < #Message Shl~text,~ !jsr 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}~ #Message Neg~text,~ !jsr StackNegate~text,~ mexit #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifparm ~1.1.4~~1.{:1}~ = ABS() ;;do ABS(olute) function @@~0~ ~1.5.{:1-5}~ #Message Abs~text,~ !jsr StackAbs~text,~ mexit #endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #ifparm ~1.1.4~~1.{:1}~ = SQR() ;;do SQR() function -- square @@~0~ ~1.5.{:1-5}~ #Message Sqr~text,~(TOS) tsx !jsr StackLoad~text,~ !jsr 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.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 ;------------------------------------------------------------------------------- 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 ;------------------------------------------------------------------------------- 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 ;------------------------------------------------------------------------------- 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 ;------------------------------------------------------------------------------- Str64 macro [Number],[ResultString] @_DoStr 64\,~1~\,~2~ endm ;******************************************************************************* ; Show the current value and size of the specified symbols ShowSym macro Symbol[,Symbol]* #Message -------------------------------------------------- mdo mswap 1,:mloop #ifdef ~1~ #Message Symbol \@~1~\@~'...................'.1.{20-:1}~ {~1~} (size: {::~1~}) #endif mloop :n endm ;******************************************************************************* ; Adds FCC string to end of ROM going backwards fcc macro String mset #',' #ifdef STRING_TOP mdef 0,{STRING_TOP} #else mdef 0,{ROM_END} #endif #push #DATA #ppc #temp :n mdo org ~text~ #ifstr ~{:temp}.~ org *-{:{:temp}-2} #else org *-1 #endif mset 0,{:pc} fcc ~{:temp}.~ #temp :temp-1 mloop :n org :ppc #pull mexit ~text~ endm ;******************************************************************************* ; Adds FCS string to end of ROM going backwards fcs macro String mset # @fcc ~1~,0 endm ;******************************************************************************* ; BSET for Pin names bset macro PinName ;BSET for Pin names mreq 1:PinName #ifz ]~1~ !bset ~1~,#~1~. #else pshx ldx #~1~ bset ,x,#~1~. pulx #endif endm ;******************************************************************************* ; BCLR for Pin names bclr macro PinName ;BCLR for Pin names mreq 1:PinName #ifz ]~1~ !bclr ~1~,#~1~. #else pshx ldx #~1~ bclr ,x,#~1~. pulx #endif endm ;******************************************************************************* ;BRSET for Pin names brset macro PinName,Address ;BRSET for Pin names mreq 1,2:PinName,Address #ifparm ~3~ !brset ~@~ mexit #endif #ifz ]~1~ !brset ~1~,#~1~.,~2~ mexit #endif #ifparm ~2~ = * mset 2,{*} #endif psha lda ~1~ anda #~1~. cmpa #~1~. pula beq ~2~ endm ;******************************************************************************* ; BRCLR for Pin names brclr macro PinName,Address ;BRCLR for Pin names mreq 1,2:PinName,Address #ifparm ~3~ !brclr ~@~ mexit #endif #ifz ]~1~ !brclr ~1~,#~1~.,~2~ mexit #endif #ifparm ~2~ = * mset 2,{*} #endif psha lda ~1~ anda #~1~.^$FF pula beq ~2~ endm ;******************************************************************************* ; Adds a new OS call to table AddOS macro Name[,AlternateLocalName] mdef 2,?~1~ #push #ROM #ifdef XROM #XROM #endif mdef 0,{:pc} #if :mindex = 1 org :pc+{MAX_OS_CALLS*2} ;;make room for so many OS calls #endif #ppc org ~text~ #ifndef OSCommands OSCommands exp * #endif f~1~ exp :mindex-1 dw ~2~ mset 0,{:pc} NUMBER_OF_OS_CALLS set :mindex ;Number of opcodes defined (so far) org :ppc #if :mindex > MAX_OS_CALLS merror {MAX_OS_CALLS} MAX_OS_CALLS, need {:mindex} (+{:mindex-MAX_OS_CALLS}) #endif #if :mindex > 256 #Warning Double byte opcodes, OS => OSW #endif #pull ;------------------------------------------------------------------------------- endm ;******************************************************************************* ; Define FLAG names (FLAG for port, FLAG. for pin number, and FLAG_ for mask) ; to be used for defining bit (boolean) flags. Flag macro [FlagBaseName (needed first time or to change name)] #ifb ~text~ #ifb ~1~ mreq 1:[FlagBaseName (needed first time or to change name)] #endif #endif #ifnb ~1~ mset 0,~1~,1,0 ;;flag base name definition (starts with suffix 1) #ifb ~label~ mexit ;;exit if no label with flag name definition #endif #endif #temp ~text','3~ #ifndef ~text,~~text','2~ #push #RAM ~text,~~text','2~ rmb 1 #pull #endif ~label~ set ~text,~~text','2~ ~label~. equ 1<~text','3~ #temp :temp+1 #if :temp < 8 mset 0,~text,~,~text','2~,{:temp} #else #temp ~text','2~+1 mset 0,~text,~,{:temp},0 #endif endm ;******************************************************************************* ; ASCII CONTROL CODES NULL def 0 ;null NUL def 0 ;Second spelling for NULL ASCII_SOH def 1 ;Start of Heading ASCII_STX def 2 ;Start of Text ASCII_ETX def 3 ;End of Text EOT def 4 ;End of Transmission ASCII_ENQ def 5 ;Enquiry ACK def 6 ;Acknowledge BELL def 7 ;Bell BS def 8 ;Backspace TAB def 9 ;Horizontal Tab LF def 10 ;Line Feed ASCII_VT def 11 ;Vertical Tab ASCII_FF def 12 ;Form Feed CR def 13 ;Carriage Return ASCII_SO def 14 ;Shift Out ASCII_SI def 15 ;Shift In ASCII_DLE def 16 ;Data Link Escape ASCII_DC1 def 17 ;Device Control 1 XON def 17 ;XON ASCII_DC2 def 18 ;Device Control 2 ASCII_DC3 def 19 ;Device Control 3 XOFF def 19 ;XOFF ASCII_DC4 def 20 ;Device Control 4 ASCII_NAK def 21 ;Negative acknowledge ASCII_SYN def 22 ;Synchronous idle ASCII_ETB def 23 ;End of Transmission Block ASCII_CAN def 24 ;Cancel ASCII_EM def 25 ;End of Medium ASCII_SUB def 26 ;CTRL-Z CTRL_Z def 26 ; -//- ESC def 27 ;Escape ASCII_FS def 28 ;File Separator ASCII_GS def 29 ;Group Separator ASCII_RS def 30 ;Record Separator ASCII_US def 31 ;Unit Separator DDR def 1 ;standard DDR offset ;---------------------------- Miscellaneous ------------------------------------ SPEED_SIZE def 2 ;1 = SPEED, 2 = SIZE optimization @ConstMinMax SPEED_SIZE,1,2 BYTE def 1 ;8-bit quantity WORD def 2 ;16-bit quantity POINTER def 3 ;24-bit (paged) pointer DWORD def 4 ;32-bit quantity QWORD def 8 ;64-bit quantity S_BYTE def 0,1 ;size of 8-bit quantity S_WORD def 0,2 ;size of 16-bit quantity S_POINTER def 0,2 ;size of pointer: 16-bit S_DWORD def 0,4 ;size of 32-bit quantity S_QWORD def 0,8 ;size of 64-bit quantity MAXERROR def 0 ;used for error codes ERASED_STATE def -1 ;default [E]EPROM/Flash Erased State REQUIRED_STACK def 50 ;required stack bytes MAX_OS_CALLS def 200 ;default room for OS calls (68HC11) ;******************************************************************************* ; Various Checks #ifdef REGS #ifnz REGS&$0FFF #Error REGS ({REGS(h)}) not in format $X000 (edit ?11E?.INC) #endif #endif ? macro FromAddress,ToAddress mdef 2,STACKTOP-REQUIRED_STACK #VARIABLE ~1~ ~2~ #Message Variable space in ~1~~' :'.{:1-2}~ {~1~(h)}-{~2~(h)} ({~2~-~1~+1} bytes) endm #ifdef RAM1 @? RAM1,RAM1_END #endif #ifdef XRAM #if STACKTOP > XRAM @? RAM,RAM_END @? XRAM #else @? RAM @? XRAM,XRAM_END #endif #else @? RAM #endif #ifdef VERSION #Message Firmware v{VERSION(2)} #endif #Message MCU Operating Voltage (VDD): {VDD(3)}V #ifz KHZ\1000 #Message {KHZ/100(1)} MHz ({BUS_KHZ/100(1)} MHz bus) Cycle: {10000000/BUS_KHZ(1)} nsec #else #Message {KHZ(3)} MHz ({BUS_KHZ(3)} MHz bus) Cycle: {10000000/BUS_KHZ(1)} nsec #endif ? macro #ifdef ~1~ #Message ~1~~'...:'.{:1-2}~ {~1~(h)}-{~1~_END(h)} ({~1~_END-~1~+1} bytes) #endif endm @? RAM #ifdef XRAM @? XRAM #endif @? EEPROM @? ROM #ifnz REQUIRED_STACK #Message STACK : {STACKTOP-REQUIRED_STACK+1(h)}-{STACKTOP(h)} [REQUIRED_STACK: {REQUIRED_STACK} bytes] #else #Message REQUIRED_STACK: None! #endif #ifdef DEBUG #Message DEBUG/SIMULATOR mode (do NOT distribute) #endif