Files
secs-gem/docs/15_e87_carriers.md
raphael 40df3067a4 docs: chapters 14–19 — GEM 300 standards (Part 2 complete)
Six more chapters finishing Part 2.  Together with chapters 10–13
they document every SEMI standard this codebase implements.

14 — E40 + E94: process jobs (8-state lifecycle, S16F11/F5/F7/F9
on the wire) and control jobs (CJ wraps PJs with batch policy,
S14F9/S16F27 messages).  Worked cascade showing how CJSTART
propagates through the PJ FSM and triggers S6F11 CEIDs at each
transition.

15 — E87 carriers: three orthogonal sub-machines (CarrierID,
SlotMap, CarrierAccess) per carrier and three more (Transfer,
Reservation, Association) per load port.  S3F17 CarrierAction
strings + CAACK codes, S3F19 SlotMap verify, the 5-state slot
encoding, multi-port concurrency.

16 — E90 + E157: substrate tracking via three orthogonal axes
(STS / SPS / SubstrateIDStatus) and module process tracking
(NotExecuting / GeneralExecuting / StepExecuting / StepCompleted).
End-to-end PVD example showing E40 + E157 + E90 transitions
cascading into CEIDs.

17 — E116 + E120 + E39: equipment performance time-buckets across
six states, common equipment model object hierarchy, S14F1/F3
GetAttr/SetAttr as the uniform wire access for any object type
across multiple standards.

18 — E84 parallel I/O: ten signal lines, the 9-state handshake
FSM, the three TA1/TA2/TA3 timing-critical timers, why a physical
handshake gets modeled in software (testability, timer enforcement,
CEID emission, multi-port concurrency), the pure-FSM + asio-adapter
split.

19 — E42 + E148 + S5F9–F18: formatted recipes (S7F23/F25 typed
PPBODY), time synchronization with 16-char + 14-char accepted on
set, exception recovery as a persistent multi-step host-supervised
FSM (Posted → Recovering → Cleared with abort/retry).  Revisits
the auto-S9 family and contrasts S9 (transport) vs S5F9
(application).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 20:14:42 +02:00

10 KiB

15 — E87: Carriers and load ports

14 E40 + E94 — Process and control jobs | Back to index | Next: 16 E90 + E157 — Substrate and module tracking

Before a wafer can be processed it has to physically arrive at the tool, dock with the load port, expose its slot contents, get verified, and be authorised by the host. That's six distinct state transitions, each one tracked by SEMI E87 — Carrier Management (2000).

This chapter covers:

  • The carrier (FOUP) and the load port — what each is and what state they each track.
  • The three carrier state sub-machines: ID, Slot Map, Access.
  • The three load-port state sub-machines: Transfer, Reservation, Association.
  • The E87 message catalog (S3F*).
  • Where each piece is in code.

Vocabulary

  • Carrier — a physical container holding wafers. In a 300 mm fab almost always a FOUP (Front-Opening Universal Pod, 25 slots). In smaller fabs sometimes a SMIF pod or a cassette.
  • Load port — the equipment-side dock where carriers physically attach. A typical PVD tool has 2 load ports (1 input, 1 output); a lithography stepper might have 4.
  • Slot map — the equipment's reading of which of the carrier's N slots contain wafers, expressed as N bytes. Slot states are Empty, CorrectlyOccupied, DoubleSlotted, CrossSlotted, NotRead.
  • Carrier ID — bar-coded string on the FOUP (e.g. "C-31415"). Read by the equipment's bar-code reader on docking.

The three carrier state sub-machines

E87 doesn't track "carrier state" as one variable — it tracks three orthogonal aspects:

1. ID Status

How sure are we who this carrier is?

// include/secsgem/gem/carrier_state.hpp:23
enum class CarrierIDStatus : uint8_t {
  NotConfirmed = 0,
  WaitingForHost = 1,
  Confirmed = 2,
  IDVerificationFailed = 3,
};

Bar-code reader fires ID_READ_OK → NotConfirmed → Confirmed. If the reader fails or returns gibberish, ID_READ_FAIL → NotConfirmed → IDVerificationFailed. Some hosts insist on verifying the ID themselves (look it up against their LMS); they hold the carrier in WaitingForHost until they reply with HOST_ID_CONFIRMED.

2. Slot Map Status

Have we read the carrier's contents?

// include/secsgem/gem/carrier_state.hpp:45
enum class SlotMapStatus : uint8_t {
  NotRead = 0,
  WaitingForHost = 1,
  Read = 2,
  SlotMapVerificationFailed = 3,
};

The mapper (an optical sensor reading wafer positions) runs after ID confirmation. Result: a 25-byte vector (one byte per slot). Hosts can validate the map against expectation (S3F19 Slot Map Verify); a mismatch flips to SlotMapVerificationFailed.

3. Access Status

Is the carrier authorised for processing right now?

// include/secsgem/gem/carrier_state.hpp:64
enum class CarrierAccessStatus : uint8_t {
  NotAccessed = 0,
  InAccess = 1,
  CarrierComplete = 2,
  CarrierStopped = 3,
};

InAccess means the equipment is currently using slots from this carrier. CarrierComplete means done; awaiting unloading.

All three sub-machines progress independently. A carrier can be Confirmed (ID) + Read (Map) + NotAccessed (Access) — and that's the typical state after docking but before the host authorises processing.

CarrierStateMachine in include/secsgem/gem/carrier_state.hpp composes the three; tests in tests/test_carrier_state.cpp (11 cases) and tests/test_e87_wire_scenarios.cpp (4 wire scenarios).


The three load-port state sub-machines

The load port has its own three sub-machines:

1. Transfer State

// include/secsgem/gem/load_port_state.hpp:19
enum class LoadPortTransferState : uint8_t {
  OutOfService = 0,
  ReadyToLoad = 1,
  ReadyToUnload = 2,
  InService = 3,
};

Physical readiness — is the port mechanically ready to dock a new FOUP, release the current one, or busy?

2. Reservation Status

enum class LoadPortReservationStatus : uint8_t {
  NotReserved = 0,
  Reserved = 1,
};

Has the host pre-reserved this port for an inbound carrier? Reservation is how the host tells the AMHS "send the carrier to this specific port."

3. Association Status

enum class LoadPortAssociationStatus : uint8_t {
  NotAssociated = 0,
  Associated = 1,
};

Is there a known Carrier object linked to this port? Becomes Associated when a carrier docks and the ID is read.

LoadPortStateMachine in include/secsgem/gem/load_port_state.hpp.


Multi-port + multi-carrier

A real fab tool runs multiple load ports in parallel. A 4-port cluster tool can have:

  • Port 1: carrier A in Associated + InAccess (processing)
  • Port 2: carrier B in Associated + CarrierComplete (done, awaiting unload)
  • Port 3: AMHS robot docking carrier C (InService)
  • Port 4: OutOfService (mechanical fault)

The codebase models this as a per-port store:

// include/secsgem/gem/store/carriers.hpp
class CarrierStore {
  // one CarrierStateMachine per Carrier ID
  // one LoadPortStateMachine per PortID
};

Tests for the parallel scenario: tests/test_e87_wire_scenarios.cpp (4 multi-port scenarios — independence between ports asserted).


The E87 messages

S/F Direction Purpose
S3F17 H → E CarrierAction. Body: CARRIERACTION + CARRIERID.
S3F18 E → H CAACK reply.
S3F19 H → E Slot Map Verify. Body: CARRIERID + expected slot states.
S3F20 E → H SMACK reply.
S3F25 H → E Carrier Transfer. Move a carrier between ports.
S3F26 E → H CAACK reply.
S3F27 H → E Cancel Carrier. Pre-arrival cancellation.
S3F28 E → H CAACK reply.

CARRIERACTION strings (S3F17 body)

The dominant E87 messages are S3F17 carrier-action commands. CARRIERACTION is an ASCII string from a fixed E87 set:

String Meaning
ProceedWithCarrier Authorise processing. Triggers Access → InAccess.
CancelCarrier Refuse the carrier; equipment doesn't process it.
CancelCarrierAtPort Same but specifies port.
BypassCarrier Process nothing from this carrier (audit slot map only).
CarrierOut Mark CarrierComplete; AMHS will retrieve.
CarrierReCID Re-read the carrier ID (e.g. bar code was iffy).

CAACK reply codes (S3F18, 1 byte):

Code Meaning
0 Acknowledged.
1 Invalid command.
2 Cannot perform now.
3 Invalid carrier ID.
4 Invalid port ID.
5 Carrier ID unknown.

A typical carrier flow

1. AMHS docks FOUP at port 1.
2. Equipment fires CarrierArrived event (CEID per equipment.yaml)
   → S6F11 (host gets pinged).
3. Equipment reads bar code → CarrierIDStatus: NotConfirmed → Confirmed.
4. Equipment runs slot mapper → SlotMapStatus: NotRead → Read.
5. (Optional) Host sends S3F19 SlotMapVerify with expected contents
   → equipment compares → SMACK = 0 (match) or 1 (mismatch).
6. Host sends S3F17 CARRIERACTION = "ProceedWithCarrier"
   → CarrierAccessStatus: NotAccessed → InAccess.
7. Processing happens.  Substrate state changes are tracked by E90
   (chapter 16).
8. All substrates done.  Equipment fires CarrierComplete event.
9. Host sends S3F17 CARRIERACTION = "CarrierOut"
   → CarrierAccessStatus → CarrierComplete.
10. AMHS retrieves FOUP from port 1.  LoadPortAssociation goes back
    to NotAssociated; carrier object can be deleted.

The slot-map-mismatch path in step 5 is tested by tests/test_e87_wire_scenarios.cpp; the happy path by tests/test_carriers.cpp (6 cases).


Slot maps in detail

A slot map is a byte-vector with one byte per carrier slot. For a 25-slot FOUP, that's 25 bytes. Byte values:

Value State Meaning
0 Empty No wafer detected.
1 CorrectlyOccupied One wafer in the correct vertical position.
2 DoubleSlotted Two wafers in one slot — physical fault.
3 CrossSlotted Wafer at an angle / wrong height.
4 NotRead Sensor couldn't read this slot.

S3F19 (Slot Map Verify) carries the host's expected slot map. The equipment compares against its read map; if they match, SMACK = 0. Mismatches imply someone interfered with the carrier (or the mapper is broken).

The map is part of the carrier store and persists across restarts.


Persistence

Like all GEM-300 stores, the carrier store is persistent. A file per active carrier + a file per port lets the equipment recover its full E87 state after a restart — including in-progress carriers stranded mid-Access by a power loss.

Tested by tests/test_carrier_persistence.cpp (6 cases — write, restart, replay, corrupted-file drop, removal).

Per-store journal pattern is the same across E40, E87, E90, E94, E116; chapter 36 walks the mechanism.


Where to go next

You now know how a carrier arrives, gets authorised, and leaves. But every wafer inside the carrier needs its own tracking — and when wafers move into a process module, their state has to follow them. That's E90 and E157.

Next: → 16 E90 + E157 — Substrate and module tracking