FANUC Custom Macro B Guide: Variables, IF/WHILE, and G65/G66 Macro Calls

27 August 2026

Mentor CNC Editör Ekibi

What is a custom macro, and how does it differ from a subprogram?

A subprogram (M98) repeats the same moves. A custom macro lets the program calculate, decide and loop. The difference in one line: a subprogram always makes the same part; a macro makes a different part depending on the dimensions you give it.

A concrete example: a bolt circle with 12 holes. With a subprogram you write 12 sets of coordinates. With a macro you supply the diameter and the number of holes, and the control works out the coordinates. When the diameter changes you change one number.

When is a macro worth writing?The same geometry recurs at different sizes · A cycle does not exist on your machine and you want to write it · A decision has to be made from a probe measurement · Values such as tool life or a part counter have to be read from the program.

Variables: four different kinds on a FANUC

A variable is written with #. The number you use determines where the variable is valid and whether it survives a power cycle. Not knowing that distinction is the most common mistake on the shop floor.

NumberTypeWhere is it valid?What happens at power off?
#0NullEverywhereAlways null, cannot be written, read only
#1 – #33Local variableOnly inside that macroCleared. Another macro using #1 cannot corrupt yours.
#100 – #199Common variable (volatile)Main program, subprograms and all macrosCleared — reset when power is removed
#500 – #999Common variable (retained)Main program, subprograms and all macrosRetained — the value survives a power cycle
#1000 and aboveSystem variableEverywhereThe control’s own data: offsets, position, alarms, clock, parameters
The distinction that mattersValues that must survive the end of a shift — a tool life counter, a part count — belong in #500–#999. Put them in #100–#199 and they reset when the machine is switched off, which you usually discover the next morning.

A note from the source manual: depending on bit 6 (NCV) of parameter 8135, the ranges #150–#199 and #550–#999 become usable. Variables in #500–#999 can also be made write protected (read only) by parameter.

Using a variable in place of an address

The value following an address can be replaced by a variable:

#33=1.5 F#33 ; the same as F1.5#18=20.0 Z-#18 ; the same as Z-20.0#130=3.0 G#130 ; the same as G3

The rules, straight from the source

  • Addresses O and N cannot take a variable. O#27 or N#1 is not allowed.
  • The n in an optional block skip /n cannot be a variable.
  • A variable number cannot be specified by a direct variable. ##30 is wrong; write #[#30].
  • No value exceeding the maximum allowable for an address can be specified. With #140=10000, G#140 is out of range.
  • Used as address data, a variable is rounded automatically. On an IS-B machine (1/1000 mm), #1=12.3456 makes G00 X#1 become G00 X12.346.
  • The decimal point can be omitted: #1=123 gives a value of 123.000.
  • Expressions are allowed: X[#24+#18*COS[#1]] or Z-[#18+#26].

The null variable trap

This causes more trouble than anything else when writing macros. A variable whose value has not been defined is called null. #0 and #3100 are always null.

1. When a null variable is quoted, the address itself is ignored

WrittenExecuted when #1 is nullExecuted when #1 = 0
G90 X100 Y#1G90 X100no Y at allG90 X100 Y0

A null variable is not the same as zero. The Y axis does not move, and no alarm is raised — it is simply skipped. This is exactly what happens when you forget to pass an argument to a macro.

2. Behaviour in assignment and arithmetic

ExpressionResult when #1 is nullResult when #1 = 0
#2 = #1 (local)null0
#2 = #1 * 500
#2 = #1 + #100
#2001 = #1 (system variable)00

Assign a null value directly and it stays null; put it through any calculation and it becomes 0. Assigned to a system variable it always becomes 0.

3. Null in comparisons

The manual’s own wording: null differs from 0 only for EQ and NE. For GE, GT, LE and LT, null is treated as equal to 0.

; with #1 null: #1 EQ #0 → true #1 NE 0 → true (note: null is not considered equal to 0) #1 GE #0 → true #1 GT 0 → false #1 LE #0 → true #1 LT 0 → false
What this means in practiceTo test whether an argument was supplied, write IF [#1 EQ #0] GOTO 99 — not IF [#1 EQ 0]. The second one also fires when the user really did enter 0.

Arithmetic operations and functions

OperationSyntaxNotes
Add / subtract#i = #j + #k · #i = #j - #k 
Multiply / divide#i = #j * #k · #i = #j / #kDivision by zero raises PS0112
Sine / cosine / tangentSIN[] · COS[] · TAN[]Angles are in degrees, not radians
Arc tangentATAN[]/[]Angle from the ratio of two values
Square rootSQRT[] 
Absolute valueABS[] 
RoundingROUND[]To the nearest integer
Truncate / round upFIX[] · FUP[]Discards the fraction / raises to the next integer
Natural log / exponentialLN[] · EXP[] 
Read a parameter#i = PRM[#j]Reads a machine parameter from the program
The most common trigonometry mistakeAngles in FANUC macros are in degrees. SIN[30] returns 0.5. Do not convert to radians.

Comparison and logic operators

FANUC macros do not use >, < or =. Two-letter abbreviations are used instead:

OperatorMeaningMaths
EQEqual to=
NENot equal to
GTGreater than>
GEGreater than or equal to
LTLess than<
LELess than or equal to

Conditions can be combined with AND and OR:

IF[[#1 EQ #2] AND [#3 EQ #4]] THEN#5=0 ; IF[[#1 EQ #2] OR [#3 EQ #4]] THEN#5=0 ;

Branching and looping: GOTO, IF, WHILE

Unconditional branch — GOTO

GOTO 1 ; ; branch to N1

Conditional branch — IF … GOTO

IF [#1 GT 10] GOTO 2 ; ; if #1 > 10, branch to N2

Conditional assignment — IF … THEN

IF [#1 EQ #2] THEN#3=0 ; ; if #1 equals #2, set #3 to 0

Looping — WHILE … DO … END

WHILE [condition] DO m ; ; m = 1, 2 or 3 ; processing END m ;

While the condition holds, everything between DO and END repeats. m can only be 1, 2 or 3.

The nesting rule — important

Nested loops may reuse the same number, but the loops must nest completely inside one another. Overlapped DO ranges raise alarm PS0124.

; CORRECT — fully nested WHILE […] DO 2 ; WHILE […] DO 1 ; END 1 ; END 2 ;; CORRECT — sequential, the same number can be reused WHILE […] DO 1 ; END 1 ; WHILE […] DO 1 ; END 1 ;; WRONG — overlapped ranges, PS0124 WHILE […] DO 1 ; WHILE […] DO 2 ; END 1 ; END 2 ;

Calling a macro: G65, G66 and G67

G65 — simple call

Calls the macro once and passes the arguments.

G65 P9100 X100.0 Y50.0 R30.0 Z-50.0 F500 ; ; P : number of the program to call ; X, Y, R, Z, F : arguments passed to the macro
RuleG65 must be specified before any argument. It cannot sit in the middle of the line.

Argument table (argument specification I)

AddressVariableAddressVariableAddressVariable
A#1I#4T#20
B#2J#5U#21
C#3K#6V#22
D#7M#13W#23
E#8Q#17X#24
F#9R#18Y#25
H#11S#19Z#26

So in the example above, inside the macro #24 = 100.0, #25 = 50.0, #18 = 30.0, #26 = −50.0 and #9 = 500.

Argument specification II

A, B and C are used once each; I, J and K can be used up to ten times each. This is the method for passing many points, for example a free-form contour. If both methods appear in one block, the type specified last takes effect.

G66 / G67 — modal call

After G66, the macro is called after every block that moves an axis, until G67 cancels it.

G66 P9100 L2 A1.0 B2.0 ; G00 X10. Y10. ; ; the macro runs after the move G00 X20. Y20. ; ; and again G67 ; ; cancel the modal call ; P : number of the program to call ; L : number of repetitions

This is very useful for hole patterns: define the drilling macro once with G66, then just write the coordinates.

Nesting limits

  • Macro calls (including G65 and G66/G66.1) can nest up to five levels.
  • Subprogram calls, macro calls included, can nest up to 15 levels.
  • Each macro call raises the local variable level by one — the inner macro’s #1 is not the outer one’s.

The mistakes people actually make

Writing persistent data into the #100 series

A part counter or tool life value in #100–#199 resets when the machine is switched off. Anything that must persist belongs in #500–#999.

Treating a null variable as zero

When an argument is not supplied the variable stays null, not zero. If #1 is null in a line reading Y#1, the Y axis does not move at all — and no alarm appears.

Writing ##30

To give a variable number with a variable, write #[#30]. ##30 is invalid.

Using a single equals sign in a comparison

IF [#1 = 10] is not valid. It must be IF [#1 EQ 10].

Overlapping WHILE loops

DO and END ranges must nest completely. A partially overlapping range raises PS0124.

Putting an NC statement and a macro statement in one block

A motion command and a macro expression on the same line raises PS0127. Put the macro expression on its own line.

Using radians in trigonometry

Angles in FANUC macros are in degrees. SIN[30] = 0.5.

Nesting macro calls deeper than five levels

The macro nesting limit is five. Beyond that you get PS0122.

Writing G65 in the middle of a line

G65 must come before all arguments.

Frequently asked questions

Does every FANUC machine have custom macro?

No, it is an option. There are two levels, Custom Macro A and Custom Macro B; B is the common one today. The quickest way to find out is to type #100=1 in MDI and run it — if the option is absent you get an alarm.

What is the practical difference between #100 and #500?

#100–#199 is for temporary arithmetic and clears at power off. #500–#999 is retained and survives a power cycle. Anything that has to carry across shifts — part counts, tool life — always goes in the #500 series.

Can I change tool offsets from the program?

Yes. Tool offsets are read and written through system variables. The numbering varies with the control series and the number of offsets, so check the system variable table in your machine’s manual. Writing a probe measurement result straight into an offset works exactly this way.

Should I use a subprogram or a macro?

If the same moves repeat identically, a subprogram (M98) is enough and simpler. If coordinates have to be calculated as the size changes, or a decision has to be made, you need a macro.

Why can I only use 1, 2 and 3 in a WHILE loop?

The DO number on a FANUC is limited to 1–3, so you can nest at most three levels of loop. In sequential (non-nested) loops the same number can be reused.

How do I protect a macro program?

Macro programs are usually stored under 9000-series program numbers (O9000–O9999), and those programs can be protected from display and editing by parameter. Common variables #500–#999 can also be made read only by parameter.

What is the equivalent of Siemens R parameters?

Roughly the FANUC #100 and #500 series common variables. Siemens additionally allows named variables via DEF; on a FANUC variables have no names, only numbers.

What do I see on screen while a macro runs?

Macro statements produce no motion, so the block display may not appear to advance. Use the control’s macro variable screen to watch the values — it is the most practical diagnostic during commissioning.

Safety warningBecause a macro calculates its motion, a wrong variable can send the tool somewhere unexpected. Every newly written macro should be checked first with graphics or dry run, then tried with no part clamped, in single block with a low feedrate override. WHILE structures that can loop forever and macros that write to system variables deserve particular supervision on their first run.
Mentor CNC note: The variable ranges, syntax and limits on this page are based on Chapter 16 of FANUC’s official Series 0i-MODEL F Operator’s Manual (B-64604EN/01). Custom macro is an optional function; whether your machine has it, which variable ranges are usable and which system variable numbers apply all depend on the control series, the options purchased and the parameter settings. The machine tool builder’s documentation always takes precedence. This page is for training purposes and does not replace the official manual.

Sources

  • FANUC — Series 0i-MODEL F, Common to Lathe System / Machining Center System, OPERATOR’S MANUAL, document no. B-64604EN/01: Section 16.1 Variables, 16.2 System variables, 16.5 Arithmetic and logic operation, 16.7 Reading parameters, 16.8 Macro statements and NC statements, 16.9 Branch and repetition (IF, GOTO, WHILE), 16.10 Macro call (G65, G66, G67), 16.13 Registering custom macro programs, 16.16 Restrictions
  • FANUC — Series 0i-MODEL F MAINTENANCE MANUAL, B-64605EN/01, Appendix A (for the macro-related PS alarms)