UNL *---------------------------------------------------------------- * TMS9995 Assembler Macros - Programmable Logic Controllers (PLC) *================================================================ * * This macro library provides opcodes available to plc * programmers. Main objective is to improve readability * and maintainability of control programs. * * Copyright (C) 2002 Erland Muller * This is free software with ABSOLUTELY NO WARRANTY. The * GNU General Public License as published by Free Software * Foundation version 2 or later applies: * http://www.fsf.org/licenses/gpl.txt * * Latest version of this file can be found at: * http://adweb.desy.de/~erlandm/tms/ctrlmacr.asm * * Maintained by: Erland Muller (erland.mueller@desy.de) * * (next paragraph will appear in the assembler listing) LIST * * Assembled with macro library permitting opcodes akin to * PLC instruction list (IL) according to DIN EN 61131-3 * * $Id: ctrlmacr.asm,v 3.7 2006-05-08 06:22:35+00 erlandm Exp $ * * Note: The current Result of the Logical Operation * (RLO) is stored in register R0 referred to as * RVKE (VKE Verknuepfungsergebnis, German for RLO) * * Warning: Macros may alter register R9 and if timer * function blocks are used, Register R11 will be * alterd too. TIMERSUB.MPO must be linked. * *----------------------------------------------------------- * UNL * * Introduction * ------------ * * The macros provide functions and function blocks of type * Boolean, which is defined as a byte (8-bit) long value, * 0 meaning "false", 0xff meaning "true". * * First input to functions and function blocks is RVKE, * further input variables are given as parameters. * The result of the logical operation is returned in * register RVKE. * * Macros do not require status flags set on entry. * On return status flags are set according to the * result of the operation. * * Storage function blocks require a symbol addressing a byte * long memory area (type bool) as a first parameter. * * Timer function blocks require a symbol addressing 6 byte * of memory area starting at an even address, which must be * initialised to zero before any first call. * * Please read "controlmacro.html" for further detail * and example code. * * Please send any comment to the author and maintainer. *----------------------------------------------------------- * * General Register Usage * RVKE EQU 0 ; Reg. VKE (Verknuepfungsergebnis) RLINK EQU 11 ; Dedicated Return Addr. Register RCRU EQU 12 ; Dedicated CRU-Address Register * * Internal Register Usage * ;RDREF EQU 9 ; Dereferencing and multipurpose reg. * * * External Declarations * REF TONS Timer Function Block Subroutines REF TOFFS REF TONOFS * *----------------------------------------------------------- * * Constants referring to data types * CTRUE EQU >FF True Constant CFALSE EQU 0 False Constant BLT$SZ EQU 1 BoolType_Size Byte CHR$SZ EQU 1 CharType_Size Byte INT$SZ EQU 2 IntegerType_Size Byte TMR$SZ EQU 6 TimerType_Size Byte PTR$SZ EQU 2 PointerType_Size Byte NULL EQU 0 NULL-Pointer * *----------------------------------------------------------- * * Macro Definiton: Function Boolean NOT * * NOT $MACRO S,T Boolean NOT UNL $IF S.A&$PCALL=0 MOVB RVKE,RVKE ; RVKE = RVKE $ELSE $IF S.S=' *' MOV :T:,;RDREF ; dereference MOVB *;RDREF,RVKE ; RVKE = *T $ELSE MOVB :S:,RVKE ; RVKE = S $ENDIF $ENDIF * ; if ( RVKE ) JEQ $+6 ; { SZCB RVKE,RVKE ; RVKE = false; JMP $+6 ; } * ; else { ORI RVKE,>FF00 ; RVKE = true; LIST ; } $END NOT * * *----------------------------------------------------------- * * Macro Definition: Bool Function cast Int to Bool * * BOOL $MACRO S,T cast int to bool UNL $IF S.A&$PCALL=0 MOV RVKE,RVKE ; set flags $ELSE $IF S.S=' *' MOV :T:,;RDREF ; dereference MOV *;RDREF,RVKE $ELSE MOV :S:,RVKE ; set flags $ENDIF $ENDIF JEQ $+6 ; zero -> false ORI RVKE,>FF00 ; otherwise -> true LIST $END BOOL * *----------------------------------------------------------- * * Macro Definition: Function ANDNOT * ANDNOT $MACRO S,T,U Boolean ANDNOT UNL $IF S.S=' *' MOV :T:,;RDREF ; dereference SZCB *;RDREF,RVKE ; RVKE = RVKE && !*T $IF U.A&$PCALL ANDNOT :U: $ENDIF $ELSE SZCB :S:,RVKE ; RVKE = RVKE && !S $IF T.A&$PCALL ANDNOT :T:,:U: $ENDIF $ENDIF LIST $END ANDNOT * *----------------------------------------------------------- * * Macro Definition: Function FALSE * FALSE $MACRO UNL SZCB RVKE,RVKE ; RVKE = FALSE LIST $END FALSE * *----------------------------------------------------------- * * Macro Definition: Function TRUE * TRUE $MACRO UNL ORI RVKE,>FF00 ; RVKE = TRUE LIST $END TRUE * *----------------------------------------------------------- * * Macro Definitions RVKE Load and Store * LD $MACRO VA,VB Load UNL $IF VA.S=' *' MOV :VB:,;RDREF ; dereference MOVB *;RDREF,RVKE ; RVKE = *VB $ELSE MOVB :VA:,RVKE:VB: ; RVKE = VA (VB diagn.) $ENDIF LIST $END LD * ST $MACRO VA,VB Store UNL $IF VA.S=' *' MOV :VB:,;RDREF ; dereference MOVB RVKE,*;RDREF ; *VB = RVKE $ELSE MOVB RVKE,:VA::VB: ; VA = RVKE (VB diagn.) $ENDIF LIST $END ST * *----------------------------------------------------------- * * Macro Definiton: Function Boolean AND * AND $MACRO PP Boolean AND UNL MOVB RVKE,RVKE ; set status flags $IF PP.A&$PCALL ;AND :PP: $ENDIF $END AND * * internal Macro ;AND: AND onto RVKE with flags allready set * ;AND $MACRO A,B,C Internal Boolean AND UNL $IF A.S=' *' indirect AND $IF (B.A&$PSYM)++(B.A&$PNDX) JEQ $+8 ; if (RVKE) { $ELSE JEQ $+6 ; if (RVKE) { $ENDIF MOV :B:,;RDREF ; RVKE = *:B: MOVB *;RDREF,RVKE ; } $IF C.A&$PCALL ;AND :C: ; ;AND recursion $ENDIF $ELSE direct AND $IF (A.A&$PSYM)++(A.A&$PNDX) JEQ $+6 ; if (RVKE) { $ELSE JEQ $+4 ; if (RVKE) { $ENDIF MOVB :A:,RVKE ; RVKE = *:B: } $IF B.A&$PCALL ;AND :B:,:C: ; ;AND recursion $ENDIF $ENDIF LIST $END ;AND * *----------------------------------------------------------- * * Macro Definition: Function Boolean OR * OR $MACRO A,B,C Boolean OR UNL $IF A.S=' *' indirect OR MOV :B:,;RDREF ; RVKE = SOCB *;RDREF,RVKE ; RVKE||*:B: $IF C.A&$PCALL OR :C: ; OR recursion $ENDIF $ELSE direct OR SOCB :A:,RVKE ; RVKE=RVKE||:A: $IF B.A&$PCALL OR :B:,:C: ; OR recursion $ENDIF $ENDIF LIST $END OR * *----------------------------------------------------------- * * Macro Definition: Function Boolean Exclusive OR * XCLOR $MACRO A,B,C Boolean XOR UNL $IF A.S=' *' indirect EXCLOR MOV :B:,;RDREF ; RVKE = MOVB *;RDREF,;RDREF ; RVKE && *:B: || XOR ;RDREF,RVKE ; !RVKE && !*:B: $IF C.A&$PCALL XCLOR :C: XCLOR recursion $ENDIF $ELSE MOVB :A:,;RDREF ; RVKE = XOR ;RDREF,RVKE ; RVKE XOR :A: $IF B.A&$PCALL XCLOR :B:,:C: XCLOR recursion $ENDIF $ENDIF MOVB RVKE,RVKE ; set status flags LIST $END XCLOR * *----------------------------------------------------------- * * Macro Definition: Set Symbolic Address * SET $MACRO A,B UNL $IF A.S=' *' MOV :B:,;RDREF SOCB RVKE,*;RDREF $ELSE SOCB RVKE,:A: $ENDIF LIST $END SET * *----------------------------------------------------------- * * Macro Definition: Reset Symbolic Address * RESET $MACRO A,B UNL $IF A.S=' *' MOV :B:,;RDREF SZCB RVKE,*;RDREF $ELSE SZCB RVKE,:A: $ENDIF LIST $END RESET * *----------------------------------------------------------- * * Macro Definiton: SR-Flipflop with Dominant Set * * Note: RVKE is Set-Input * SR $MACRO QS,R,T F-Block-Address,Reset,Set UNL $IF QS.S=' *' ;SRIND :S:,:T: $ELSE SZCB :R:,@:QS: ; QS = !R && QS SOCB RVKE,@:QS: ; QS = S || QS MOVB @:QS:,RVKE ; Q = QS $ENDIF LIST $END SR * ;SRIND $MACRO QS,R MOV :QS:,;RDREF ; dereference SZCB :R:,*;RDREF ; *QS = !R && *QS SOCB RVKE,*;RDREF ; *QS = S || *QS MOVB *;RDREF,RVKE ; Q = *QS $END ;SRIND * *----------------------------------------------------------- * * Macro Definition: RS-Flipflop with Dominant Reset * * Note: RVKE is Set-Input * RS $MACRO QS,R,T F-Block-Address,Set,Reset UNL $IF QS.S=' *' ;RSIND :R:,:T: $ELSE SOCB RVKE,@:QS: ; QS = S || QS SZCB :R:,@:QS: ; QS = !R && QS MOVB @:QS:,RVKE ; Q = QS $ENDIF LIST $END RS * ;RSIND $MACRO QS,R MOV :QS:,;RDREF ; dereference SOCB RVKE,*;RDREF ; *QS = S || *QS SZCB :R:,*;RDREF ; *QS = !R && *QS MOVB *;RDREF,RVKE ; Q = *QS $END ;RSIND * *----------------------------------------------------------- * * Macro Definiton: Trigger on Rising (Leading) Edge * RTRIG $MACRO A,B Trigger Rising Edge UNL $IF A.S=' *' MOV :B:,;RDREF CB *;RDREF,RVKE JNE $+6 SZCB RVKE,RVKE JMP $+4 MOVB RVKE,*;RDREF $ELSE CB @:A.S:,RVKE ; if (VKE == QS) JNE $+6 ; { SZCB RVKE,RVKE ; Q = 0 JMP $+6 ; } * ; else { MOVB RVKE,@:A.S: ; QS = VKE $ENDIF LIST ; } $END RTRIG * *----------------------------------------------------------- * * Macro Definiton: Trigger on Falling (Trailing) Edge * FTRIG $MACRO A,B Trigger Falling Edge UNL $IF A.S=' *' MOV :B:,;RDREF MOVB RVKE,RVKE JEQ $+8 MOVB RVKE,*;RDREF SZCB RVKE,RVKE JMP $+8 MOVB *;RDREF,RVKE JEQ $+4 SZCB RVKE,*;RDREF $ELSE MOVB RVKE,RVKE ; if (VKE) JEQ $+10 ; { MOVB RVKE,@:A.S: ; VKES = VKE SZCB RVKE,RVKE ; Q = 0 JMP $+12 ; } * ; else { MOVB @:A.S:,RVKE : if (Q = VKES) /*not ==*/ JEQ $+6 ; { SZCB RVKE,@:A.S: ; VKES = 0 * ; } $ENDIF LIST ; } $END FTRIG * *----------------------------------------------------------- * * Macro Definiton: Toggle * TOGLE $MACRO BA UNL MOVB RVKE,RVKE ; if ( VKE ) JEQ $+22 ; { NOT @:BA.S: ; Q = NOT QS (14 Byte) UNL MOVB RVKE,@:BA.S: ; QS = Q JMP $+6 ; } * ; else { MOVB @:BA.S:,R0 ; Q = QS LIST ; } $END TOGLE * * *=========================================================== * * Timer Function Block Macro Definitions * *----------------------------------------------------------- * Erland Muller * 08/05/02 * * The timer macros implement the common plc function blocks * for time delayed switching on, off or both. They are * called eg. as: * * TON TimerBlock,TimeLimit,TimeMultiplierConstant * * with Register RVKE beeing the boolean input to be delayed * TimerBlock the even address of 3 words RAM, which * can be any of the assembler addressing * modes but immediate and indirection * operator addressed (the 1st Word must * be initialised to 0) * TimeLimit the const unsigned int time limit in * units of @SLCNT (see below) * TimeMultiplierConstant the multiplier of TimeLimit * * on return RVKE contains the boolean output * * Side effects: Registers RLINK and ;RDREF are changed * * Preconditions: @SLCNT an unsigned int counter continuously * is incremented at constant time intervals * from 0 or 1 up to some const unsigned int * MAXCNT whereupon it is reset to its * inital value. * TimeLimit < MAXCNT minus time intervall * between succesive calls upon TimerBlock * * The macros call timer subroutines "timersub.asm", which * should be assembled separately. These make external * reference to SLCNT and MAXCNT, which must be defined by * the multi tasking system or monitor. * * Note: On RTMT 4.0 SLCNT is incremented every ms while * multi tasking is enabled only * MAXCNT = 31000 * * More detail will be given in "controlmacro.html" and * timersub.asm *----------------------------------------------------------- * * Register Usage of Timer Macros * RVKE EQU 0 ; RLO (Result of Logical Operation) ;RDREF EQU 9 ; Macro Dereferencing Register RLINK EQU 11 ; dedicated register return adrress * *----------------------------------------------------------- * * Macro TON (Delay Switch On) * TON $MACRO A,B,C UNL $IF A.S=' *' MOV :B:,;RDREF ; ;RDREF = &timer ;TMACR TONS,:C: ; timer macro $ELSE LI ;RDREF,:A: ; ;RDREF = &Timer ;TMACR TONS,:B:,:C: ; timer macro $ENDIF LIST $END TON * *----------------------------------------------------------- * * Macro TOFF (Delay Switch Off) * TOFF $MACRO A,B,C UNL $IF A.S=' *' MOV :B:,;RDREF ; ;RDREF = &timer ;TMACR TOFFS,:C: ; timer macro $ELSE LI ;RDREF,:A: ; ;RDREF = &Timer ;TMACR TOFFS,:B:,:C: ; timer macro $ENDIF LIST $END TOFF * *----------------------------------------------------------- * * Macro TONOFF (Delay Switch On and Off) * TONOFF $MACRO A,B,C UNL $IF A.S=' *' MOV :B:,;RDREF ; ;RDREF = &timer ;TMACR TONOFS,:C: ; timer macro $ELSE LI ;RDREF,:A: ; ;RDREF = &Timer ;TMACR TONOFS,:B:,:C: ; timer macro $ENDIF LIST $END TONOFF * *----------------------------------------------------------- * * Internal General Timer Macro (called by TON, TOFF, TONOFF * ;TMACR $MACRO TS,TL,TM CB RVKE,*;RDREF+ ; RVKE == QS ? JEQ $+10 ; yes, -> VKES := Q BL @:TS: ; no, call timer subroutine DATA :TL: ; with TimeLimit $IF TM.A&$PCALL DATA :TM: ; and TimeMultiplier $ELSE DATA 1 ; or standard Multipl. $ENDIF MOVB RVKE,*;RDREF ; VKES := Q $END ;TMACR ; Subroutine returns here! * * End of the Timer Function Block Macro Definitons * *=========================================================== * * * Macro Definition: Intermittent Signal (Flasher) * * Note: F-Block-Address must address 12 byte momory area * BLINK $MACRO BL,TH,TL F-Block-Address,T-High,T-Low UNL MOVB @:BL.S:,RVKE TON :BL.S:+6,:TH.S: UNL NOT RVKE UNL TON :BL.S:,:TL.S: LIST $END BLINK * *----------------------------------------------------------- * * Macro Definition: Immediate Load of Input * LINP $MACRO BV,IX Load Boolean Variable with InpX UNL CLR RVKE VKE = false TB :IX.S: if (EQ) JNE $+4 { SETO RVKE VKE = true * } MOVB RVKE,:BV.S: BV = VKE LIST $END LINP *----------------------------------------------------------- * * Macro Definition: Filtered Load of Input * * Delay via TONOFF * LINPD $MACRO TI,ZT,BV,IX Load Bool Variable with InpX UNL CLR RVKE VKE = false TB :IX.S: if ( IX ) //EQ set if IX=1 JNE $+4 { SETO RVKE VKE = true * } TONOFF :TI.S:,:ZT.S: VKE = TONOFF(VKE, Time) UNL MOVB RVKE,:BV.S: BV = VKE LIST $END LINPD * *----------------------------------------------------------- * * Macro Definition: Filtered Load of Inverted Input * * Delay via TONOFF * LINPDN $MACRO TI,ZT,BV,IX Load Bool Variable with !InpX UNL CLR RVKE VKE = false TB :IX.S: if ( ! IX ) //EQ set if IX=1 JEQ $+4 { SETO RVKE VKE = true * } TONOFF :TI.S:,:ZT.S: VKE = TONOFF(VKE, Zeit) UNL MOVB RVKE,:BV.S: BV = VKE LIST $END LINPDN * *----------------------------------------------------------- * * Macro Definition: Output * OUTP $MACRO BV,QX output Bool Variable to OutX UNL MOVB :BV.S:,RVKE if ( BV ) JEQ $+6 { SBO :QX.S: QX = 1 //true JMP $+4 } * else { SBZ :QX.S: QX = 0 //false LIST } $END OUTP * *----------------------------------------------------------- * * Macro Definition: Load of Memory Flags (Bits) * Expects Address in RCRU * LMEMF $MACRO BV,IX Boolean Variable with Bit IX UNL MOV *RCRU,;RDREF ;RDREF = *RCRU LI RVKE,:IX.S:+1 for (i=IX+1;i>0;i--) SRL ;RDREF,0 shift rigth into Carry JNC $+8 if ( Carry ) { ORI RVKE,>FF00 RVKE = true JMP $+4 } * else { SZCB RVKE,RVKE RVKE = false * } MOVB RVKE,:BV.S: LIST $END LMEMF * *----------------------------------------------------------- * * End of Control Macro Definitons * *----------------------------------------------------------- * LIST