אופן מעינה

**אופני מעינה** או **אופני מיעון** () הם היבט של ארכיטקטורת ערכת ההוראות ברוב יחידות העיבוד המרכזיות (CPU). אופני המעינה השונים, המוגדרים בארכיטקטורת סט פקודות נתונה, מגדירים כיצד הוראות שפת המכונה בארכיטקטורה זו מתייחסות אל כל אחד מהאופרנדים בפקודה נתונה – האם האופרנד מייצג נתון מספרי, כתובת או מספר אוגר וכדומה. אופן המעינה מציין כיצד לחשב את **[[כתובת (זיכרון מחשב)|כתובת הזיכרון]] בפועל** (memory effective address) של אופרנד באמצעות שימוש במידע שבאוגרים, בקבועים הכלולים בהוראת המכונה או במקום אחר.

בתכנות מחשבים, אופני מעינה חשובים בעיקר עבור מתכנתים המתכנתים בשפות סף ועבור כותבי מהדרים. **סט פקודות אורתוגונלי**  הוא סט פקודות שבו כל הוראה יכולה להתבצע בכל אופני המעינה בקיימים בארכיטקטורה.

## סייגים
בדרך כלל אין שמות אחידים לאופני המעינה השונים; ארכיטקטים של מחשבים ויצרני מחשבים שונים עשויים לתת שמות שונים לאותו אופן מעינה, או שם אחד לאופני מעינה שונים. יתרה מזאת, אופן מעינה שבארכיטקטורה נתונה פועל כאופן מעינה יחיד עשוי לייצג פונקציונליות שבארכיטקטורה אחרת דורשת שני אופני מעינה או יותר. לדוגמה, בכמה ארכיטקטורות מחשבים בעלות סט פקודות מורכב (CISC), כגון VAX של חברת דיגיטל, התייחסות לאוגרים והתייחסות לקבועים מיידיים (כלומר קבועים הנמצאים בפקודה עצמה) נחשבות כשני אופני מעינה של אותה הוראה. במחשבים אחרים, כגון IBM System/360 ובממשיכיו, וברוב המחשבים עם סט פקודות מצומצם (RISC), מידע זה מקודד בתוך ההוראה עצמה. כלומר, למחשבים האחרונים יש הוראות נפרדות עבור העתקת אוגר אחד למשנהו, עבור העתקת קבוע מפורש לתוך אוגר ועבור העתקת נתון מזיכרון לתוך אוגר, בעוד של-VAX יש רק הוראת "MOV" אחת בעלת כמה אופני מעינה.

המונח "אופן מעינה" עצמו נתון לפרשנויות שונות: יש שמגדירים אותו כ"אופן חישוב כתובת זיכרון" ויש שמגדירים אותו כ"אופן גישה לאופרנד". לפי ההגדרה הראשונה, הוראות שאינן קוראות מהזיכרון או כותבות לזיכרון (כגון הוראה להוספת קבוע לאוגר) לא נחשבות בעלות "אופן מעינה". ההגדרה השנייה מאפשרת למחשבים כגון VAX, המשתמשים בסיביות מצב אופרנד (operand mode bits) בהוראה, להגדיר אם האופרנד נמצא באוגר או שהוא ערך קבוע. עם זאת, רק ההגדרה הראשונה רלוונטית עבור הוראות כגון "טען כתובת בפועל", הוראה שמוֹרה למחשב לטעון את הכתובת עצמה במקום את הנתון שבכתובת זו.

אופני המעינה המפורטים להלן מחולקים למעינות עבור קוד (הוראות) ולמעינות עבור נתונים. רוב ארכיטקטורות המחשבים שומרות על הבחנה זו, אבל ישנן ארכיטקטורות המאפשרות להשתמש בכל אופן מעינה כמעט בכל הקשר.

ההוראות המוצגות להלן באות להמחיש את אופני המעינה, ואינן משקפות בהכרח את התחביר המשמש מחשב מסוים.

לחלק מהמחשבים, כמו IBM 709 ו־RCA 3301, אין שדה אופן מעינה יחיד אלא שדות נפרדים עבור מעינה עקיפה ועבור שימוש באינדקס.

## מספר אופני המעינה
מספר אופני המעינה משתנה מאוד בין ארכיטקטורות מחשבים שונות. ישנם כמה יתרונות בביטול אופני מעינה מורכבים ובשימוש באופן מעינה יחיד בלבד או בכמה פשוטים, אף על פי שדבר זה דורש כמה הוראות נוספות, ואולי אף אוגר נוסף. הוכח שקל הרבה יותר לתכנן מעבדים העובדים בשיטת צינור עיבוד נתונים אם אופני המעינה הם פשוטים.

לרוב ארכיטקטורות ה־RISC יש כ־5 אופני מעינה פשוטים, בעוד שלמחשבי ארכיטקטורות CISC, כגון VAX של דיגיטל, יש יותר מתריסר אופני מעינה, חלקם מורכבים למדי. לארכיטקטורת IBM System/360 היו רק 3 אופני מעינה; עוד כמה נוספו עבור System/390.

כאשר יש מספר מועט של אופני מעינה, אופן המעינה המסוים הנדרש מקודד בדרך כלל בתוך קוד ההוראות (למשל ב־IBM System/360 וממשיכיו, ורוב ה־RISC), כלומר יש הוראה נפרדת עבור אופן מעינה שאינו מובנה. כאשר ישנם אופני מעינה רבים, לעיתים קרובות יש שדה ספציפי בהוראה שמציין את אופן המעינה. ה-DEC VAX אִפשר כמעט לכל ההוראות לעבוד עם אופרנדים מרובים של זיכרון (כלומר שהוראה בודדת עשויה לגשת או לשנות נתונים המאוחסנים במספר מיקומי זיכרון), ולכן הוא שמר את הסיביות הראשונות בכל שדה אופרנד בהוראה כדי לציין את אופן המעינה עבור האופרנד המסוים הזה. תכנון זה אִפשר פעולות מגוונות על מיקומי זיכרון שונים בתוך הוראה יחידה, והגביר את גמישות הארכיטקטורה ואת יעילותה.

אפילו במחשבים בעלי אופני מעינה רבים, מדידות של תוכניות בפועל מצביעות על כך שאופני המעינה הפשוטים המפורטים להלן מהווים כ-90% או יותר מכלל אופני המעינה שבשימוש. מכיוון שרוב המדידות הללו מבוססות על קוד שנוצר משפות עיליות על ידי מהדרים, הדבר משקף במידה מסוימת את מגבלות המהדרים שבשימוש.

## יישום מעשי חשוב
כמה ארכיטקטורות סט פקודות, כגון אינטל x86 ו-IBM/360 וממשיכיה, כוללות הוראת **כתובת בפועל** (effective address) לטעינת נתונים. הוראה זו מחשבת את כתובת האופרנד בפועל וטוענת אותה לתוך אוגר, מבלי לגשת לכתובת זיכרון שאליו היא מתייחסת. דבר זה יכול להיות שימושי בעת העברת הכתובת של ערך מתוך מערך לתת-שגרה. זו עשויה להיות גם דרך חכמה לבצע יותר חישובים בהוראה יחידה. לדוגמה, שימוש בהוראה כזו עם אופן המעינה "בסיס + אינדקס + היסט" (מפורט להלן) מאפשר לבצע פעולת חיבור של שני אוגרים וקבוע בהוראה אחת ולאחסן את התוצאה באוגר שלישי.

## אופני מעינה פשוטים עבור קוד
כמה אופני מעינה פשוטים לקוד מוצגים להלן. המינוחים עשוים להשתנות בהתאם לפלטפורמה.

### מעינה מוחלטת או ישירה
ב**מעינה מוחלטת** או **ישירה** (Absolute or direct), הכתובת בפועל עבור כתובת פקודה ישירה היא פרמטר הכתובת עצמו, ללא שינויים כלשהם.

### מעינה יחסית
ב**מעינה יחסית** (PC-relative), הכתובת בפועל היא כתובת ההוראה הבאה בתוספת ההיסט. היסט הוא מספר, חיובי או שלילי ("מספר מסומן"), המאפשר להתייחס לקוד שמופיע אחרי ההוראה או לפניה.

דבר זה שימושי במיוחד בקפיצות, מכיוון שקפיצות טיפוסיות קופצות להוראות סמוכות (בשפה עילית, ברוב הפקודות המותנות (**if**) ובלולאות ה־**while** הקפיצות הן קצרות למדי). מדידות בפועל תוכניות מצביעות על כך שהיסט של 8 או 10 סיביות (בערך ±128 או ±512 בתים) מספיק לכ־90% מהקפיצות המותנות.

יתרון נוסף של המעינה היחסית הוא שהקוד יכול להיות בלתי תלוי במיקום, כלומר ניתן לטעון אותו בכל מקום בזיכרון ללא צורך לשנות בו כתובות כלשהן.

גרסאות מסוימות של אופן מעינה זה עשויות להיות מותנות בתוכן של שני אוגרים ("קפוץ אם reg1=reg2"), בתוכן אוגר יחיד ("קפוץ אלא אם כן reg1=0") או ללא אוגרים בכלל, תוך התייחסות הרומזת לאיזושהי סיבית שהוצבה קודם לכן באוגר הדגלים. ראו גם ביצוע מותנה להלן.

### מעינת אוגר עקיפה
ב**מעינת אוגר עקיפה** (Register indirect), הכתובת בפועל היא תוכן האוגר שצוין בפקודה. לדוגמה, בפקודה `jump (A7)` המעבד ניגש לאוגר הכתובת A7, וקופץ לכתובת הנמצאת בו.

למחשבי RISC רבים, כמו גם למחשב ה־CISC IBM System/360 ולבאים אחריו, יש הוראות קריאה לתת-שגרות ששומרות את כתובת החזרה באוגר כתובת – מעינת אוגר עקיפה משמשת לחזרה לתוכנית הראשית מאותה תת-שגרה.

## אופני מעינה פשוטים עבור נתונים
כמה אופני מעינה פשוטים לנתונים מוצגים להלן. המינוחים עשוים להשתנות בהתאם לפלטפורמה.

### מעינת אוגר ישירה
ל**מעינת אוגר ישירה** (register direct; נקראת גם מעינת אוגר) אין כתובת בפועל, ובמחשבים מסוימים היא אינה נחשבת לאופן מעינה.

בדוגמה זו, כל האופרנדים נמצאים באוגרים, והתוצאה נכתבת לאוגר.

### מעינה מיידית או מפורשת
ל**מעינה מיידית** או **מפורשת** (Immediate or literal) אין כתובת בפועל, ובמחשבים מסוימים היא אינה נחשבת לאופן מעינה.

הקבוע עשוי להיות חיובי בלבד או בעל סימן. לדוגמה, `move.l #$FEEDABBA, D0` כדי להעביר את הערך ההקסדצימלי המיידי "FEEDABBA" לתוך האוגר D0.

במקום להשתמש באופרנד מהזיכרון, הערך של האופרנד נמצא בתוך ההוראה עצמה. במחשב VAX של חברת DEC, האופרנד המפורש יכול להיות באורך של 6, 8, 16 או 32 סיביות.

אנדרו טננבאום  הראה ש-98% מכל הקבועים בתוכנית יתאימו ל-13 סיביות (ראוRISC).

### בסיס עם היסט
ב**מעינת בסיס עם היסט** (Base plus offset), הכתובת בפועל היא תוכן אוגר הבסיס בתוספת ההיסט. ההיסט הוא ערך חיובי או שלילי של 16 סיביות (בערך ±32 קילו־בייט אם כי ב־80386 הוא הורחב ל-32 סיביות – בערך ±2 גיגה־בייט).

אם ההיסט הוא אפס, המעינה הופכת למקרה פרטי של **מעינת אוגר עקיפה** משום שהכתובת בפועל היא פשוט הערך שבאוגר הבסיס.

במחשבי RISC רבים, ערכו של אוגר 0 הוא תמיד אפס ולא ניתן לשנותו. אם משתמשים באוגר 0 כאוגר הבסיס, הכתובת בפועל היא ההיסט והמעינה הופכת למקרה פרטי של **[[#מעינה מוחלטת או ישירה|מעינה ישירה]]**. עם זאת, ניתן לגשת בדרך זו רק לחלק קטן מהזיכרון (64 קילובייט, אם ההיסט הוא של 16 סיביות).

היסט של 16 סיביות עשוי להיראות קטן מאוד ביחס לגודל זיכרונות המחשב בימינו (ולכן ב־80386 הוא הורחב ל-32 סיביות), אך המצב יכול להיות גרוע יותר: למחשבי המיינפריים של IBM System/360 יש היסט חיובי בלבד של 12 סיביות. עם זאת, עקרון המקומיות חל: לאורך זמן קצר, רוב פריטי הנתונים שתוכנית רוצה לגשת אליהם קרובים למדי זה לזה.

לדוגמה, בתוך תת-שגרה, מתכנת יתעניין בעיקר בפרמטרים ובמשתנים המקומיים, שרק לעיתים רחוקות יהיו במרחקים העולים על 64 קילו־בייט. עבורם מספיק אוגר בסיס אחד – מצביע המסגרת. אם שגרה זו היא שיטת מחלקה (class method) בשפה מונחית עצמים, אז קיים צורך באוגר בסיס נוסף שמצביע על תכונות האובייקט הנוכחי (`this` או `self` בשפות עיליות מסוימות).

דוגמה נוספת, אם אוגר הבסיס מכיל את הכתובת של טיפוס נתונים מורכב (רשומה או מבנה), ניתן להשתמש בהיסט לבחירת שדה באותו הטיפוס (גודלם של רוב הרשומות והמבנים הוא פחות מ־32 קילו־בייט).

אופן מעינה זה קשור בקשר הדוק למעינה ישירה ממופתחת (indexed absolute addressing).

### מרמזת
ב**מעינה מרמזת** או **משתמעת** (Implicit), הכתובת בפועל למקור או ליעד (ולפעמים עבור שניהם) אינה מצוינת במפורש.

המקור (אם בכלל יש מקור) או כתובת היעד בפועל (ולפעמים שניהם) משתמעים מתוך קוד הפעולה.

מעינה מרמזת הייתה נפוצה למדי במחשבים ישנים (עד אמצע שנות ה-70). למחשבים כאלה היה בדרך כלל רק אוגר בודד שבו ניתן לבצע פעולות אריתמטיות – הצובר. מכונות צובר כאלה מתייחסות באופן מרומז לאותו צובר כמעט בכל הוראה. לדוגמה, את הפעולה `a := b + c;` ניתן לעשות באמצעות הרצף `load b; add c; store a;` – היעד (הצובר) מרומז בכל הוראת טעינה (load) וחיבור (add); המקור (גם הצובר) מרומז בכל הוראת אחסון (store).

למחשבים מאוחרים יותר, היו בדרך כלל יותר מאוגר רב תכליתי יחיד או מיקום RAM יחיד שיכולים להיות המקור או היעד או שניהם עבור פעולות אריתמטיות, ולכן מחשבים מאוחרים יותר צריכים אופני מעינה אחרים כדי לציין את המקור ואת היעד של האריתמטיקה.

מתוך סט הפקודות של ה־x86, חלק מהפקודות עושות שימוש באוגרים מרומזים עבור אחד מהאופרנדים או התוצאות (כגון בכפל, חילוק וספירת קפיצות מותנית).

למחשבים רבים (כגון x86 ו-AVR) יש אוגר אחד למטרות מיוחדות הנקרא מצביע המחסנית (stack pointer), אשר מוגדל או מופחת באופן מרומז בעת דחיפה (push) או שליפה (pop) של נתונים מהמחסנית, והכתובת בפועל של המקור או של היעד היא (באופן מרומז) הכתובת המאוחסנת במצביע מחסנית.

למחשבי 32 סיביות רבים (כגון 68000, ARM או PowerPC) יש יותר מאוגר יחיד שיכול לשמש כמצביע מחסנית, ולכן משתמשים באופן המעינה "מעינת אוגר מוגדל אוטומטית עקיפה" (register autoincrement indirect) כדי לציין באיזה אוגר יש להשתמש כאשר דוחפים או שולפים נתונים ממחסנית.

כמה ארכיטקטורות מחשבים נוכחיות (כמו IBM/390 ופנטיום) מכילות כמה הוראות עם אופרנדים מרומזים על מנת לשמור על תאימות לאחור עם מעבדים קודמים. במחשבים רבים, הוראות שהופכות את סיבית מצב המשתמש/מערכת, סיבית אִפשור פסיקות (interrupt-enable) וכו' רומזות לאוגר המיוחד שבו נשמרות סיביות אלו.

כמה מעבדים תוכננו באופן כזה כך שכל אופרנד תמיד מצוין באופן מרומז בלבד בכל הוראה שהיא. מעבדים אלו נקראים **מעבדים ללא מען** (zero-operand CPUs).

## אופני מעינה סדרתיים
### ביצוע סדרתי
**הוראה סדרתית** (sequential instruction) היא הוראה שאחרי ביצועה המעבד מבצע מיד את ההוראה הבאה שבזיכרון. הכתובת בפועל היא כתובת ההוראה הבאה. במחשבים מסוימים, ביצוע סדרתי של הוראות אינו נחשב לאופן מעינה. רוב ההוראות ברוב הארכיטקטורות הן הוראות סדרתיות, ולכן מתכנני מעבדים מוסיפים לעיתים קרובות תכונות שמקריבות בכוונה את ביצועי ההוראות האחרות – כמו הוראות הסתעפות (קפיצות וקריאות לתת-שגרות) – על מנת לגרום להוראות הסדרתיות לרוץ מהר יותר.

הסתעפויות מותנות טוענות למונה התוכנית (PC) אחת משתי תוצאות אפשריות, בהתאם לתנאי. אם התנאי מתקיים, ההסתעפות מתרחשת – מונה התוכנית נטען בכתובת חדשה. אם התנאי אינו מתקיים, התוכנית ממשיכה בביצוע ההוראה הסדרתית הבאה (ההסתעפות לא מתרחשת). ברוב הארכיטקטורות, הסתעפות שמתרחשת נחשבת למקרה מיוחד שמצריך טיפול נוסף, אך בהסתעפות שלא מתרחשת, המעבד פשוט ממשיך בביצוע הסדרתי הרגיל.

תכונות רבות במעבדים מודרניים כגון קדם-אחזור (prefetch) של הוראות והצנרה מורכבת יותר, ביצוע שלא לפי הסדר וכו', שומרות על האשליה שכל הוראה מסתיימת לפני שההוראה הבאה מתחילה, ושהתוצאות הסופיות הן אותן תוצאות, אף על פי שזה לא בדיוק מה שקורה בתוך החומרה.

כל "בלוק בסיסי" של הוראות סדרתיות כאלה מציג את עקרון המקומיות גם בזמן וגם במרחב.

#### מעבדים שאינם משתמשים בביצוע סדרתי
מעבדים שאינם מבצעים הוראות באופן סדרתי באמצעות מונה תוכנית הם נדירים ביותר. בחלק ממעבדים אלו, בכל הוראה תמיד מצוינת כתובת ההוראה הבאה. למעבדים כאלה יש מצביע הוראה שמצביע על הכתובת שצוינה; מצביע זה איננו מונה תוכנית משום שאין מנגנון מובנה להגדלתו. מעבדים כאלה כוללים כמה מחשבי זיכרון תופים  כמו IBM 650, מכונת SECD, ליברסקופ LGP-30 ו־RTX 32P.

ארכיטקטורות מחשוב אחרות הולכות הרבה יותר רחוק, ומנסות לעקוף את צוואר בקבוק פון־נוימן באמצעות מגוון חלופות למונה התוכניות.

### ביצוע מותנה
בחלק מארכיטקטורות המחשב יש הוראות מותנות (כגון ב־ARM) או הוראות טעינת נתונים מותנות (כגון ב־x86), כלומר הוראות שמתבצעות אם תנאי מסוים מתקיים. במקרים מסוימים הוראות כאלו יכולות לייתר הסתעפויות מותנות ולמנוע ריקון פתאומי (flushing) של צינור ההוראות. הוראה כגון 'השווה' (compare) קובעת את ערכם של חלק מהדגלים באוגר הדגלים על פי תוצאת ההשוואה, והוראות מותנות עוקבות כוללות בדיקה של הדגלים האלה כדי לראות אם הם מקיימים את התנאי או לא.

### דילוג
**מעינת דילוג** (Skip) עשויה להיחשב כסוג מיוחד של מעינה יחסית עם היסט קבוע של 1+. כמו למעינה יחסית, גם למעינה זו יש, במעבדים מסוימים, גרסאות שמותנות בערכו של אוגר אחד בלבד (`skip if reg1=0`) או שלא מותנות באוגרים בכלל אלא מותנות באופן מרומז באיזשהו ביט באוגר הדגלים שערכו נקבע קודם לכן. במעבדים אחרים יש גרסה שבוחרת סיבית מסוימת בבייט מסוים ובודקת את ערכו ("דלג אם סיביות 7 של reg12 היא 0").

בניגוד לכל ההסתעפויות המותנות האחרות, הוראת דילוג לעולם אינה צריכה לרוקן באופן פתאומי את צינור ההוראות, אם כי ייתכן שהיא תצטרך לגרום להתעלמות מההוראה הבאה – דילוג.

## מונחון
* נתון **מפורש** (immediate) – נתון המפורש בהוראה
* נתון **ישיר** (direct) – נתון שכתובתו נתונה
* נתון **עקיף** (indirect) – נתון שכתובתו מאוחסנת בכתובת מסוימת או במצביע
* **היסט** (offset) – ערך הנוסף לכתובת באופן מפורש.
* **אינדקס** (index) – היסט הניתן לשינוי. נמצא בדרך כלל באוגר אינדקס.
* **כתובת יחסית** (relative) – כתובת שנוצרה ביחס לכתובת אחרת.

## ראו גם
* ארכיטקטורת סט פקודות
* אפיק כתובת

## קישורים חיצוניים
* אופני מעינה בשפת סף
* אופני מעינה

## הערות שוליים

קטגוריה:ארכיטקטורת מחשב