code wiki / _hdl_build / nx_litho_stepper.nx
nx_litho_stepper.nx
buildroot/runtime/_hdl_build/nx_litho_stepper.nx
about
nx_litho_stepper.nx -- Arc D1: MASKLESS-STEPPER CONTROL (the chip-fab exposure step; the assignment
generator queued this). A maskless stepper is an XY motion stage + a UV source that EXPOSES the mask
pattern (nx_mask_geom) onto photoresist, field by field. The control loop is EXPOSURE DOSE -- the
direct analog of the jam-physics gate:
dose (mJ/cm^2) = intensity (mW/cm^2) * time (s). The resist clears only inside a DOSE WINDOW:
UNDER-dose -> resist never clears -> MISSING features (the litho "too cold")
OVER-dose -> features BLOOM, the critical dimension blows out, neighbors SHORT (litho "too hot")
Over/under exposure also BIASES the critical dimension (CD): actual_CD = drawn_CD + dose-bias; a
layout that passed DRC can still fail in resist if the dose is wrong.
FOCUS: the stage Z must hold the pattern within the depth of focus or features blur.
The S-class RECIPE GATE names the failing cause (UNDER_DOSE / OVER_DOSE / OUT_OF_FOCUS / CD_OUT) --
the same "tell me WHERE the hardware is failing" discipline as nx_jam_check, now for lithography.
Composes nx_mask_geom (pattern + CD) + nx_motion_plan (field stepping) + nx_metrology. Units:
dose mJ/cm^2, intensity mW/cm^2, time ms, lengths nm. LAWS: struct-free, integer-only.
license_tier: ORIGINAL
dependencies 3 imports · 1 importers
imports: nx_mask_geom.nxnx_motion_plan.nxnx_syscalls.nx
imported by: nx_litho_stepper_test.nx
structs
| none |
consts
| 20 | const LS_OK: i64 = 0 |
| 21 | const LS_UNDER_DOSE: i64 = 1 // resist won't clear -> missing features |
| 22 | const LS_OVER_DOSE: i64 = 2 // features bloom / short -> CD blowout |
| 23 | const LS_OUT_OF_FOCUS: i64 = 3 // Z beyond depth of focus -> blur |
| 24 | const LS_CD_OUT: i64 = 4 // critical dimension out of tolerance after dose bias |
functions
| 28 | func ls_exposure_time_ms(target_dose_mJ: i64, intensity_mW: i64) -> i64 called by 1: main |
| 34 | func ls_actual_dose_mJ(intensity_mW: i64, time_ms: i64) -> i64 |
| 39 | func ls_dose_verdict(dose_mJ: i64, dose_min: i64, dose_max: i64) -> i64 |
| 46 | func ls_cd_bias_nm(dose_mJ: i64, nominal_dose_mJ: i64, k_nm_per_mJ: i64) -> i64 |
| 51 | func ls_actual_cd_nm(drawn_cd_nm: i64, dose_mJ: i64, nominal_dose_mJ: i64, k_nm_per_mJ: i64) -> i64 |
| 56 | func ls_cd_in_tol(drawn_cd_nm: i64, actual_cd_nm: i64, tol_nm: i64) -> i64 |
| 64 | func ls_in_focus(z_error_nm: i64, depth_of_focus_nm: i64) -> i64 |
| 73 | func ls_field_count(wafer_w: i64, wafer_h: i64, field_w: i64, field_h: i64) -> i64 called by 1: main |
| 82 | func ls_total_exposure_ms(n_fields: i64, expose_ms: i64, step_settle_ms: i64) -> i64 called by 1: main |
| 88 | func ls_recipe_check(intensity_mW: i64, time_ms: i64, dose_min: i64, dose_max: i64, nominal_dose: i64, |