M98 and M99 Subprograms in CNC Milling

19 July 2026

Mentor CNC Editör Ekibi

If the same operation is repeated in several places in a CNC program, writing out every move again and again makes the program long. Instead, the repeated section can be prepared as a separate program. This separate section is called a subprogram, and the program that calls it is the main program.

Subprograms are especially useful for machining the same hole group in different areas, repeating the same slot at several points, using the same contour at different workpiece zeros, repeating a movement a set number of times and making long programs tidier.

Main Program and Subprogram

The main program manages the overall machining sequence of the part; it usually contains the safe start codes, tool call, spindle and coolant commands, the workpiece zero, the subprogram call lines and the program end.

%
O1000
G17 G21 G40 G49 G80 G90
T01 M06
G54
S1500 M03
G00 X20 Y20
G43 H01 Z50
M08
M98 P2000
G00 Z50
M09
M05
M30
%

Here the line M98 P2000 calls subprogram number O2000. The subprogram is the separate program that holds the moves to be reused:

%
O2000
G81 Z-15 R2 F120
X50 Y20
X80 Y20
G80
M99
%

The M99 at the end of the subprogram completes the operation and returns control to the block after the M98 line in the main program.

The M98 Command and the P Address

M98 is the subprogram-call command. The common FANUC-type format is M98 P2000, meaning “run subprogram O2000 once”. In simple use, P is the subprogram number to call. However, the way P is written can differ between controls; on some systems the program number and the repeat count are coded within the same P value. Always check the machine’s programming manual.

The M99 Command

M99 ends the subprogram and returns to the program that called it. When the control reaches M99, it returns to just after the M98 line in the main program. If M30 is used at the end of a subprogram by mistake, the whole program can end. The basic distinction is:

CodeFunction
M98Calls the subprogram
M99Returns from the subprogram
M30Ends the main program and rewinds
M02Ends the program

Simple M98–M99 Example

The main program prepares the tool; the subprogram runs a rectangular tool path:

(MAIN PROGRAM)
%
O1000
G17 G21 G40 G49 G80 G90
T01 M06
G54
S1800 M03
G00 X20 Y20
G43 H01 Z50
M08
M98 P2000
G00 Z50
M09
M05
M30
%

(SUBPROGRAM)
%
O2000
G00 Z5
G01 Z-2 F100
G01 X60 F300
G01 Y40
G01 X20
G01 Y20
G00 Z20
M99
%

Running a Subprogram Several Times

On some FANUC-type controls the repeat count is written with the L address: M98 P2000 L4 can run subprogram O2000 four times. On other systems the repeat count is prepended to the P address; for example M98 P00042000 can, on some systems, call O2000 four times. Since the format differs between controls, it must not be copied directly.

Using the Same Subprogram at Different Positions

If a subprogram contains only fixed coordinates, it runs at the same place every time it is called. There are three basic ways to use it at different positions: go to a different start point in the main program, use G91 incremental motion in the subprogram, or use different workpiece zeros. At beginner level the clearest method is to move to the new position in the main program and call the subprogram from there.

Using a subprogram with G91

Moves written under G91 are applied relative to the current position, so the same tool path can be reused at different start points.

(MAIN PROGRAM)
%
O1100
G17 G21 G40 G49 G80 G90
T01 M06
G54
S2000 M03
G00 X20 Y20
G43 H01 Z50
M08
M98 P2100
G90 G00 X80 Y20
M98 P2100
G00 Z50
M09
M05
M30
%

(SUBPROGRAM)
%
O2100
G91
G00 Z-45
G01 Z-2 F100
G01 X30 F250
G01 Y20
G01 X-30
G01 Y-20
G00 Z47
G90
M99
%

The subprogram forms the same rectangle relative to the current start point. The Z moves here only show the training logic; in a real program the safe Z levels must be verified for the part and machine.

Why G90 and G91 Matter in a Subprogram

If G91 is used inside a subprogram and G90 is not called before the end, control can return to the main program in incremental mode. Then the main program’s G00 X100 Y50 line, instead of going to X100 Y50, can move 100 mm in X and 50 mm in Y from the current position. So a subprogram must return the important modal states it changed to a safe state before ending (for example, start with G91 and end with G90).

Machining a Hole Group with a Subprogram

Suppose the same group of three holes exists in two different areas:

(MAIN PROGRAM)
%
O1200
G17 G21 G40 G49 G80 G90
T02 M06
G54
S1400 M03
G00 X20 Y20
G43 H02 Z50
M08
M98 P2200
G00 X80 Y20
M98 P2200
G00 Z50
M09
M05
M30
%

(SUBPROGRAM)
%
O2200
G91
G98 G81 Z-15 R2 F120
X20
X20
G80
G90
M99
%

The first hole is drilled at the tool’s current position before the subprogram is called; the next two are 20 mm apart in X. But the interpretation of Z and R under G91 must be carefully verified for the control; at beginner level, separate absolute-coordinate subprograms for drilling cycles can be safer.

Should a Tool Be Changed Inside a Subprogram?

It is technically possible on some systems, but at beginner level it is tidier to change tools in the main program. The main program manages the tool, spindle, G54, G43 H, coolant and safe start; the subprogram holds only the repeated machining moves. This split makes the program easier to read and simplifies tracking which tool, offset and speed are used.

Nested Subprograms

A subprogram can call another subprogram (for example M98 P3000 inside O2000). However, the depth of nesting is limited by the control’s capacity. Excessive nesting makes the program hard to follow and can cause return errors, a call-level alarm or a wrong repeat count. At beginner level, a simple structure with few layers should be preferred.

Infinite Loop and “Subprogram Not Found” Alarms

If M99 is used by mistake at the end of the main program, the program can return to the start and, depending on the control, keep restarting. Likewise, if a subprogram calls itself (M98 P2000 inside O2000), an infinite call can occur or the control alarms. The main program should generally end with M30 and the subprogram with M99.

If M98 P2500 is called but O2500 is not in memory, the control can raise a “subprogram not found” alarm. Check: is the program number correct, is the subprogram loaded into memory, is there a zero/digit error in the number, was the subprogram left on another device? When a main program is moved to another machine, the linked subprograms must be transferred too.

Common Subprogram Mistakes

  • Using M30 instead of M99 (the whole program ends when the subprogram finishes)
  • Using M99 at the end of the main program (the program keeps returning to the start)
  • Leaving G91 active (later coordinates in the main program are applied wrongly)
  • Calling the wrong subprogram number (“not found” alarm)
  • Forgetting the safe Z move (the tool can hit the part/fixture on its way)
  • Mismanaging G41/G42 (returning with compensation still active)
  • Not writing G80 (the drilling cycle carries into the main program)
  • Calling the same subprogram at the wrong start point

Safe Subprogram Writing Rules

  • Clearly separate the main and subprogram numbers; put an operation comment at the top of the subprogram.
  • Define the G90/G91 state clearly; return modal states to a safe state at the end of the subprogram.
  • Cancel drilling cycles with G80 and cutter compensation with G40 at a suitable point.
  • Use M99 at the end of the subprogram and M30 at the end of the main program.
  • On the first run, use graphic simulation, Single Block and low Rapid Override.

Mentor CNC Disclaimer and Safety Notice

The format of the M98, M99, P and L addresses can differ between controls. In particular, prepending the repeat count to the P address, the nesting limit and the use of canned cycles under G91 must be verified from the machine’s programming manual. New subprograms should be tested for the first time with graphic simulation, Single Block and low Rapid Override.