חזור לתיקייה: 00440252 - מערכות ספרתיות ומבנה המחשב

7 - מבנה המחשב

חיפוש בתיקיה
Ctrl K
לחץ כאן או הקש Ctrl K כדי לחפש בכל התיקיה
  • מודל וון נאומן
  • תוצאה 1: לכל יש כתובת
  • ייצוג הפקודות
  • סיכום הפקודות
  • בונים מחשב
  • מבצעים פקודות
  • שולטים בלוגיקה
  • תזמון פעולות
  • מחשב Multi-Cycle
  • ביצועים
  • מממשים את מכונת המצבים
  • חריגות ופסיקות(Interapts)
  • Pipeline
  • שליטה ב-Pipeline
  • סכנות בצנרור(Hazards)

7 - מבנה המחשב

00440252

מערכות ספרתיות ומבנה המחשב

רשימות הרצאה לקריאה בשבת

מבנה המחשב

הופק מתוך תקיית התואר של שקד

uni-folder.vercel.app

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

מודל וון נאומן

מודל זה מספר לנו כמה דברים על המחשב:

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

מחשבים שעובדים לפי מודל זה נקראים מחשבי von  Neumannvon\;NeumannvonNeumann.

תוצאה 1: לכל יש כתובת

הכל מאוחסן בזכרון, גם מידע וגם הוראות ופקודות. לכן, להכל יש כתובת בזכרון.
מצביעים הם פשוט כתובת בזכרון.
רגיסטר אחד יכול לשמור את הכתובת של ההוראה שמתבצעת - לכתובת זו קוראים PCPCPC לשום Program  CounterProgram\;CounterProgramCounter.

רוב המידע שנעבוד איתו יהיה בקבוצות של 323232 ביטים.

הערה

הפקודות lwlwlw ו-swswsw נותנות גישה לזכרון פר מילה. (כלומר, אי אפשר לגשת לאמצע מילה כהתחלה)

ייצוג הפקודות

ב-RISC−VRISC-VRISC−V כל מילה היא 323232 ביטים. למען הפשטות, גם פקודות הן 323232 ביטים ולכן מילה אחד בלבד.
כשאנו כותבים add x10,x11,x0 אין לזה באמת משמעות לחומרה. נרצה לתת משמעות לכך ולשם כך אנו מתרגמים אסמבלי לקוד מכונה.

יש לנו שישה סוגים של הוראות אשר לכל סוג תצורה שונה של כתיבה:

  • RRR - פעולות חישוביות המקבלות שני רגיסטרים.
  • III - פעולות חישוביות המקבלות רגיסטר ומספר קבוע.
  • SSS - אחסון
  • BBB - ענפים (התפצלות)
  • UUU - [משהו שלא הבנתי]
  • JJJ - קפיצות.

הפורמטים עבורם הינם:
​ספרתיות הרצאה אסמבלי על מחשב - 1.png

ה-opcodeopcodeopcode אומר לנו מה היא הפקודה בדיוק.
בסוג RRR:

  • הערכים של opcode,funct3,funct7opcode,funct3,funct7opcode,funct3,funct7 אומרים לנו בדיוק מה אנו צריכים לעשות. ⟸ למה זה לא ערך אחד שאומר לנו מה לעשות? נראה בהמשך.
  • הערכים rs1,rs2rs1,rs2rs1,rs2 אומרים אילו רגיסטרים מכילים את האופרנדים.
  • הערך rdrdrd מבהיר איזה רגיסטר מקבל את התוצאה.
  • כל בלוק רגיסטר מאחסן מספר שלם ללא סימן ברוחב 555 ביטים. (מה שמתאים בדיוק ל-323232 רגיסטרים)
דוגמה

עבור הקוד:

add x18,x19,x10

נקבל את:

funct7rs2rs1funct3rdopcode00000000101010011000100100110011\begin{array}{|c|c|c|c|c|c|} \hline funct7 & rs2 & rs1 & funct3 & rd & opcode \\ \hline 0000000 & 01010 & 10011 & 000 & 10010 & 0110011 \\ \hline \end{array}funct70000000​rs201010​rs110011​funct3000​rd10010​opcode0110011​​

ובאופן כללי:
​ספרתיות הרצאה אסמבלי על מחשב - 2.png

מה קורה עם פעולות עם מספר קבוע(מסוג III)? איך הן מאחסנים מספרים קבועים ממש ממש גדולים? זה בדיוק למה זה פעולה מסוג אחר - כי אנו צריכים את המקום.
בסוג III נקבל שבמקום funct7funct7funct7 יש לנו פשוט מקום לשים את המספר הקבוע שלנו באורך 121212 ביטים.

הערה

  • הקבוע הוא תמיד עם סימן!!!!!
  • בנוסף, בהמשך נראה כיצד אנו מתמודדים עם מספרים גדולים יותר מ-121212 ביטים
דוגמה

נסתכל על הפקודה:

addi x15,x1,-50

ונרשום אותה כך:

imm[11:0]rs1funct3rdopcode11111100111000001000011110010011\begin{array}{|c|c|c|c|c|} \hline imm[11:0] & rs1 & funct3 & rd & opcode \\ \hline 111111001110 & 00001 & 000 & 01111 & 0010011 \\ \hline \end{array}imm[11:0]111111001110​rs100001​funct3000​rd01111​opcode0010011​​

ובאופן כללי:
​ספרתיות הרצאה אסמבלי על מחשב - 3.png

הערה

הפקודות עם shamtshamtshamt מבצעים הזזה של מספר קבוע.
ההזזה יכולה להיות מקסימום 313131 ביטים ולכן אנו יכולים לתאר אותה באמצעות 555 ביטים בלבד.

פקודות הטעינה שונות במקצת אך הן עדיין פקודות III:
​ספרתיות הרצאה אסמבלי על מחשב - 5.png

פקודות אחסון, מפורמט SSS נראות כך:
​ספרתיות הרצאה אסמבלי על מחשב - 6.png
זה נראה מאוד דומה למה שראינו עד כה - המבנה זהה.
מהו ההבדל בעצם שיש לנו פה? לקחו את 121212 הסיביות ופיצלו אותם ל-imm[4:0]imm[4:0]imm[4:0] ול-imm[11:5]imm[11:5]imm[11:5].
הפיצול נובע מבהירות הכתיבה: אין שום רגיסטר תוצאה בפקודות storestorestore, יש לנו שני רגיסטרי מקור. לכן, כדי להשתמש באותם חיווטים של החומרה, נדרש ששני רגיסטרי המקור יצביעו לרגיסטרי המקור בפקודה.
עבור ה-destdestdest אין שימוש, ולכן נוכל לקחת את המקום שלו ולהשתמש בו עבור המקום שלנו בזכרון.

דוגמה

עבור הפקודה:

sw x14, 8(x2)

נקבל:

offset[11:5]rs2rs1funct3imm[4:0]opcode000000000111000010010010000100011\begin{array}{|c|c|c|c|c|c|} \hline offset[11:5] & rs2 & rs1 & funct3 & imm[4:0] & opcode \\ \hline 00000000 & 01110 & 00010 & 010 & 01000 & 0100011 \\ \hline \end{array}offset[11:5]00000000​rs201110​rs100010​funct3010​imm[4:0]01000​opcode0100011​​

ובאופן כללי:
​ספרתיות הרצאה אסמבלי על מחשב - 7.png

הערה

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

פקודות השוואה ועינוף(שליחה לענפים) - אלו מהסוג BBB - לא כותבות לשום מקום, אלא רק קוראות ואז קופצות.
ה-LabelLabelLabel בפקודה אינו כתובת אבסולוטית, אלא, ביחס למקום בו אנו נמצאים כרגע.
⟸ אנו משתמשים באיזור ה-imm[4:0],imm[11:5]imm[4:0],imm[11:5]imm[4:0],imm[11:5] על מנת לאחסן את הכתובת היחסית בתצורת המשלים לשתיים. ⟸ ניתן עם פקודות אלו לקפוץ עד מקסימום של 2112^{11}211 פקודות למעלה או למטה.
לאור העובדה שיש לנו 121212 סיביות ואנו קופצים בקבוצות של 222 בתים, הסיבית הראשונה תמיד תהיה אפס ולכן, המחשב ימלא אותה בעצמו תמיד.
מבנה הפקודות הוא בתכלס:
​ספרתיות הרצאה אסמבלי על מחשב - 8.png
כאשר בחומרה נקבל:
​ספרתיות הרצאה אסמבלי על מחשב - 9.png

דוגמה

עבור סט הפקודות:

Loop: beq x19,x10,End
       add x18,x18,x10
       addi x19,x19,-1
       j Loop
End:

פקודת ההשוואה תהיה:

imm[12]imm[10:5]rs2rs1BEQimm[4:1]imm[11]BRANCH00000000101010011000100001100011\begin{array}{|c|c|c|c|c|c|c|c|} \hline imm[12] & imm[10:5] & rs2 & rs1 & BEQ & imm[4:1] & imm[11] & BRANCH \\ \hline 0 & 000000 & 01010 & 10011 & 000 & 1000 & 0 & 1100011 \\ \hline \end{array}imm[12]0​imm[10:5]000000​rs201010​rs110011​BEQ000​imm[4:1]1000​imm[11]0​BRANCH1100011​​

ובאופן כללי:
​ספרתיות הרצאה אסמבלי על מחשב - 10.png

הערה

אם נרצה לקפוץ למקום מאוד רחוק, נשתמש בפקודות ה-JJJ שיכולות לעשות זאת.

bne x10,x0,next
j far
next: #next instruction

הפקודות מסוג UUU הינן: LUILUILUI ו-AUIPCAUIPCAUIPC.
מטרת הפקודות האלו היא הכנסת מספר קבוע לתוך רגיסטר.
הפקודות האלו תמיד עובדות בזוג שכן לא ניתן לאחסן 323232 ביטים של מידע בנוסף לפקודה עצמה.

  • הפקודה LUILUILUI משמשת לבניית קבועים של 323232 ביטים והיא נראית כך:
    ​ספרתיות הרצאה אסמבלי על מחשב - 11.png
    זה ממלא את 121212 הביטים הכי נמוכים עם אפסים ומאפשר לנו לשנות את 202020 הסיביות הכי גבוהות(MSBMSBMSB).
    ביחד עם addiaddiaddi ניתן למלא את 121212 הסיביות האחרות כך:
    lui x10, 0x87654   # x10=0x87654
    addi x10,x10,0x321 # x10=0x87654321
    

עם הדבר הזה יש בעיה ולשם כך נראה דוגמה:

lui x10, 0xDEADB    # x10=0xDEADB000
addi x10,x10, 0xEFF # x10=0xDEADAEEF

נשים לב כי ה-BBB הוחלפה לנו עם AAA. למה זה קורה? בגלל ש-EEE יוצר 111 בהתחלה, ה-addiaddiaddi חושב שזה מספר שלילי ומרחיב אותו עם 111-ים, מה שיוצר לנו בעיה שכן החיבור לא עובד יותר.

על מנת לסדר את זה, יצרו פסודו פקודה שמסדר את הבעיה הזו באמצעות תרגום והיא liwliwliw. כך לא נתעסק בכלל עם הפקודה luiluilui שצריכה שתי פקודות.

דוגמה

liw x10, 0xDEADBEEF
  • הפקודה AUIPCAUIPCAUIPC מקבלת מספר, מחברת אותו ל-PCPCPC ואז שמה אותו ברגיסטר.

בפורמט ה-JJJ יש שתי פקודות: jaljaljal ו-jalrjalrjalr.

  • מבנה הפקודה jaljaljal הינו:
    ​ספרתיות הרצאה אסמבלי על מחשב - 12.png
הערה

  • הפקודה jjj היא פסודו פקודה והיא בעצם משתמשת ב-jaljaljal ומבצעת rd=x0rd=x0rd=x0 כדי שלא ישאר מיקום חזרה.
  • מכיוון שיש לנו פה רק רגיסטר אחד ואופקוד, נוכל לקפוץ ל-±218\pm2^{18}±218 פקודות של 323232 ביטים.
  • מבנה הפקודה jalrjalrjalr הינו:
    ​ספרתיות הרצאה אסמבלי על מחשב - 13.png
    אשר מחבר את הערך של rs1rs1rs1 וה-immimmimm ותבצע השמה של תוצאת החיבור ל-PCPCPC. (שזוהי הקפיצה)
    נשים לב כי זה לא יחסי.
    פה אין שום מנגנון של הוספת אפסים מימין. כדי להגדיל את המספר, מגדילים את rs1rs1rs1.

סיכום הפקודות

​ספרתיות הרצאה אסמבלי על מחשב - 14.png

בונים מחשב

כעת, לאחר שראינו כיצד אנו מבצעים פקודות ומאחסנים דברים בזכרון נדבר על איך זה עובד באמת בחומרה.
המחשב הוא מערכת עקיבה בתכלס, אשר ה-FFFFFF-ים שלה הם האורגים(רגיסטרים) שלה(מהם יש 323232 אשר אחד מהם 000 קבוע)
בכל עליית שעון, המחשב מבצע פעולה אחת.
⟸ הפלט הנוכחי משנה את הפלט של השלב הבא, וזה למה זו מערכת עקיבה ולא צירופית.
זה נראה כך:
​ספרתיות הרצאה 10 - 1.png
משמאל נוכל לראות את ה-PCPCPC שלנו ובנוסף, יחידה היכולה להוסיף אליו 444.
התהליך מתחלק ל-5 חלקים:

  1. קריאת פקודה.
  2. קריאת הערכים מהזכרון והשמתם לאוגרים
  3. ביצוע הפעולה(באמצעות ה-ALUALUALU)
  4. כתיבה מחדש לזכרון.
  5. כתיבה מחדש לאוגרים. (בעצם אנו שומרים את הכל בזכרון ואז כותבים מהזכרון לאוגרים)
הערה

זה סרטוט עקרוני וחסרים בו מלא דברים(כגון כניסת בחירה ל-muxmuxmux)

מבצעים פקודות

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

נתחיל מהפקודה add rd, rs1, rs2 אשר משנה בשני דרכים את המערכת:
א. Reg[rd]=Reg[rs1]+Reg[rs2]Reg[rd]=Reg[rs1]+Reg[rs2]Reg[rd]=Reg[rs1]+Reg[rs2] (ביצוע החישוב)
ב. PC=PC+4PC=PC+4PC=PC+4 (כדי להתקדם לפקודה הבאה)

מה אנו צריכים בשביל פקודת addaddadd?

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

זה יראה כך:
​ספרתיות הרצאה 10 - 3.png
נסתכל כעת על התזמונים של מערכת זו:
​ספרתיות הרצאה 10 - 4.png

עכשיו נרצה להוסיף פעולת חיסור הנראת כך: sub rd, rs1, rs2.
המימוש שלה כמעט זהה ולכן נוכל להשתמש בכמעט כל הרכיבים באותו הדבר, רק נדרש לרכיב שמבצע חיסור במקום חיבור.
נשים לב כי על פי מה שראינו ברשימת הפקודות, ההבדל בין חיבור לחיסור הוא inst[30]inst[30]inst[30] אשר אם הוא 111 אזי הוא חיסור.
לכן, מפאת קיום ההבדל הזה, נוכל לקחת רכיב אשר יכול לבצע גם חיבור וגם חיסור ולתת לו את inst[30]inst[30]inst[30] כמי שמבדיל בין חיבור לחיסור.
כך, יהיה לנו מחשב שיוכל לעשות גם חיבור וגם חיסור:
​ספרתיות הרצאה 10 - 5.png

ברגע זה אנו יכולים לבצע את כל הפקודות מהסוג RRR שראינו קודם.
כעת, נעבור להוסיף פקודות מסוג III ונתחיל בפקודה addi x15,x1,-50.
מה שחסר לנו במה שבנינו עד כה על מנת לממש סדרה של חיבורים שכן המספר הקבוע יכול להיות בגודל של עד ±211\pm 2^{11}±211 שזה גדול מ-323232 סיביות.
לכן, יהיה לנו יצור בשם Immidiate  GeneatorImmidiate\;GeneatorImmidiateGeneator אשר יחלק את את המספר, לחצי השני יבצע Sign  extentionSign\;extentionSignextention ואז יאפשר חיבור שלהם כך:
​ספרתיות הרצאה 10 - 6.png

כעת, לאחר שיש לנו יכולת לבצע פקודות מסוג RRR ומסוג III, נרצה לממש פקודות הקוראות מהזכרון כדוגמת lw x14, 8(x2).
לפקודות אלו אותו פורמט כמו פקודות ה-III אך הן עושות משהו שונה עם התוצאה של החישוב ⟸ היא קוראת מהזכרון ומציבה את המה שנקרא ברגיסטר שהוזן.
אנו צריכים כעת רכיב חדש הכותב לזכרון או קורא ממנו בנקודה ספציפית. זה יראה כך:
​ספרתיות הרצאה 10 - 7.png

הערה

מה שכתוב בשרטוט AddA,AddrB,…AddA,AddrB,\dotsAddA,AddrB,… זה לא באמת כתובת אלא פשוט רגיסטר A,B,…A,B,\dotsA,B,….

הערה

כדי שנוכל לממש גם את lblblb נוכל להוסיף מנגנון שמבצע Sign  ExtentionSign\;ExtentionSignExtention למה שיוצא מהזכרון DMEMDMEMDMEM.

כעת, נתעסק עם פקודות מהסוג SSS אשר הן פקודות אחסון. נתחיל מהפקודה הבסיסית ביותר sw x14, 8(x2).
לשם כך יש לנו כבר את כל מה שאנחנו צריכים כי אנו יכולים לאחסן בזכרון את מה שאנו רוצים עם ה-DMEMDMEMDMEM.
הדבר היחיד ששונה הוא שנדרש דרך להכניס ערך ל-DMEMDMEMDMEM ולא רק כתובת.
​ספרתיות הרצאה 10 - 8.png
החוט הכחול הוא בדיוק מה שאנו צריכים כדי שגם פקודות האחסון יעבדו.

הערה

נשים לב כי ה-Imm.GenImm.GenImm.Gen עובד שונה על בסיס האם הפקודה היא III או SSS ולכן, אנו מכניסים אליו גם חוט אשר אומר לו באיזה מצב אנחנו כדי שיוכל ליצור את הקבוע כמו שצריך.

כעת נעבור לפקודות עינוף, כלומר, פקודות מסוג BBB. פורמט זה כמעט זהה לפורמט SSS עם שני אוגרי מקור וקבוע באורך 121212 ביטים.
עכשיו, בנוסף, הקבוע מייצג קפיצה של 2⋅value2\cdot value2⋅value ביטים(ולא ביט אחד)
​ספרתיות הרצאה 10 - 10.png
נשים לב כי גם פקודות העינוף דורשות קבוע שהוא קבוע ה-offsetoffsetoffset לקפיצה וגם הוא נבנה באופן קצת שונה מהאחרים.

כעת, נממש את jalr rd, rs, immediate אשר כותבת PC+4PC+4PC+4 אל Reg[rd]Reg[rd]Reg[rd], מבצעת PC=Reg[rs1]+immPC=Reg[rs1]+immPC=Reg[rs1]+imm.
השימוש פה בקבוע הוא כקבוע רגיל ולא ככפולות של 222.
לשם כך אנו צריכים דרך לחבר בין PC+4PC+4PC+4 לרגיסטרים כדי לרשום את הערך לתוך הרגיסטר. זה יראה כך:
​ספרתיות הרצאה 10 - 11.png

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

הפקודות הבאות הן מסוג UUU אשר מאפשרות לנו להסתכל על 202020 הסיביות ה-MSBMSBMSB של רגיסטר.
לפקודות אלו לא צריך להוסיף דברים במעגל שיצרנו.

שולטים בלוגיקה

נרצה כעת לראות איך מממשים את הבקר הזה שראינו שהיה קופסה שחורה עד כה.
לבקר יש טבלת אמת יחסית גדולה:
​ספרתיות הרצאה 10 - 12.png

נקח ROMROMROM(זכרון לקריאה בלבד) ובאמצעות בחירה של מיקום הקריאה הנכון, נוציא את הערך הנכון לכל חוט.
כדי לממש אותו אנו נשתמש במפענח בתצורה כזו:
​ספרתיות הרצאה 10 - 13.png

תזמון פעולות

כעת, לאחר שיש לנו בקר ומבצע פעולות שבנינו ממקודם, נוכל להסתכל על כמה זמן לוקח התהליך הזה של ביצוע פקודה.
​ספרתיות הרצאה 10 - 14.png
נסתכל על ערכים רגילים של זמנים:

IFIDEXMEMWBTotalI−MEMReg  ReadALUD−MEMReg  W200ps100ps200ps200ps100ps800ps\begin{array}{|c|c|c|c|c|c|} \hline IF & ID & EX & MEM & WB & Total \\ \hline I-MEM & Reg\;Read & ALU & D-MEM & Reg\;W \\ \hline 200ps & 100ps & 200ps & 200ps & 100ps & 800ps \\ \hline \end{array}IFI−MEM200ps​IDRegRead100ps​EXALU200ps​MEMD−MEM200ps​WBRegW100ps​Total800ps​​

נשים לב כי ps=10−9sps=10^{-9}sps=10−9s ולכן המעבד שלנו יכול לבצע מלאאא פקודות בשנייה אחת.

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

מחשב Multi−CycleMulti-CycleMulti−Cycle

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

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

עד כה ראינו אוגרים אשר מחזיקים מידע לזמן לא ידוע, כעת, עבור ה-Muli−CycleMuli-CycleMuli−Cycle שלנו, נשתמש באוגרים אשר מחזיקים מידע למשך ביצוע של פקודה אחת. לא ניתן לגשת לאוגרים אלו מהמחשב עצמו, והם רק משמשים את המערכת עצמה.

כעת, נשים את האוגרים האלו בכל אחד הקווים הכחולים:
​מערכות ספרתיות - מחשב multiCycle - תמונה מספר 1.png
בעצם חילקנו את המעבד לשלבים.
​מערכות ספרתיות - מחשב multiCycle - תמונה מספר 2.png
כך נראת מכונת המצבים של מעבד זה.

נשים לב כי כעת, מכיוון שאנו שומרים את התוצאות, אנו יכולים לוותר על ה-Branch  CompareBranch\;CompareBranchCompare שכן נוכל במחזור שעון אחד לבדוק האם אנחנו רוצים לקפוץ, ואז עם כן, נוכל לחשב את מיקום הקפיצה במחזור השעון הבא.
באותו האופן עם ה-pc+4pc+4pc+4 שלנו.
לכן, המחשב שלנו יראה כך:
​מערכות ספרתיות - מחשב multiCycle - תמונה מספר 3.png

אנו שומרים את PCCPCCPCC שהוא הערך הנוכחי של PCPCPC מכיוון שיש פקודות שהוא נדרש בהן לחישוב, נניח beqbeqbeq וכדומה.

כל פקודה מבוצעת מעט שונה וכל שלב שלה מעט שונה, אבל באופן כללי:
​מערכות ספרתיות - מחשב multiCycle - תמונה מספר 4.png

כעת נרצה לבנות את הבקר ולשם כך תהיה לנו מכונת מצבים:
​מערכות ספרתיות - מחשב multiCycle - תמונה מספר 5.png

ביצועים

ב-MultiCycleMultiCycleMultiCycle כל פקודה דורשת מספר מחזורים שונה:

  1. פקודות טעינה 555 מחזורים.
  2. פקודת אחסון 4 מחזורים.
  3. פקודת חשבון 4 מחזורים.
  4. פקודת עינוף 3 מחזורים.
  5. פקודת קפיצה 3 מחזורים.

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

מממשים את מכונת המצבים

[מה אפילו קרה פה????]

חריגות ופסיקות(InteraptsInteraptsInterapts)

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

  1. התוכנית עצמה.
  2. בעיות בביצוע התוכנית.
  3. גורם מחוץ למעבד.

המושגים הללו אינה אוניברסליים ובכל מחשב נהוגות הגדרות מעט שונות.

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

כאשר מתרחשת חריגה, מערכת ההפעלה יכולה לעשות כל מיני דברים שונים ולאחר שהיא עשתה אותם, היא תחזור לתוכנית המקורית באחת מהדרכים הבאות:

  • לחדש מיידית את ביצוע התוכנית בפקודה בה נגרמה החריגה. (שחזור כל הרגיסטרים!)
  • להעביר את התוכנית לסוף תור תוכניות הממתינות לחידוש הביצוע.
  • להפסיק את ביצוע התוכנית ולעבור לתוכנית אחרת.

[להשלים מהמצגת]

PipelinePipelinePipeline

עד כה אנו ראינו מעבד SingleCycleSingleCycleSingleCycle ומעבד MultiCycleMultiCycleMultiCycle.
אנו חילקנו את ביצוע הפעולה ל-555 שלבים אשר ביחד לוקח להם זמן כלשהו.
נרצה כעת לייעל שוב את המעבד שלנו לאחת מהצורות היעילות ביותר שאפשר - הצורה היעילה ביותר שנלמד בקורס.

נשים אוגרים אמיתיים ולא זמניים בין חלק לחלק ואז, כאשר פקודה תסיים שלב אחד, נעביר אותה לשלב הבא ונכניס לשלב הנ"ל את הפקודה הבאה כדי לשפר את ה-ThroughputThroughputThroughput :)
ה-ThroughputThroughputThroughput שנקבל הוא פי 444 יותר טוב מה-MultiCycleMultiCycleMultiCycle או ה-SingleCycleSingleCycleSingleCycle.
​המשך הדוגמה מספרתיות.png

על מנת לבנות את המחשב החדש הזה שלנו, נתחיל ממודל ה-SingleCycleSingleCycleSingleCycle שכן כל דבר צריך להיות מבוצע פעם אחת שכן המידע תמיד זורם.
​שם רנדומלי לקובץ כנראה מתרגול ספרתיות.png
נשים לב כי חסרים לנו כמה דברים על מנת לבצע את הצנרור שאנו כה רוצים - אנו רוצים לשמור את כל הפרמטרים של הפקודה ונראה איך עושים זאת כעת:
​עוד משהו כנראה מתרגול ספרתיות של החברה.png
כרגע לא איכפת לנו מכמות החומרה, אנו פשוט רוצים מחשב מהיר.

שליטה ב-PipelinePipelinePipeline

בארכיטקטורת הצנרור (PipelinePipelinePipeline), סיגנלי הבקרה מיוצרים בשלב הפענוח (DecodeDecodeDecode), בדיוק כמו במעבד ה-SingleCycleSingleCycleSingleCycle
אך מכיוון שכל פקודה מתקדמת שלב אחד בכל מחזור שעון, אנו לא יכולים להשתמש בכל סיגנלי הבקרה מיד. הפתרון הוא להעביר את סיגנלי הבקרה הלאה יחד עם הפקודה עצמה דרך אוגרי ה-PipelinePipelinePipeline.
בכל שלב, המעבד עושה שימוש רק בסיגנלים הרלוונטיים לאותו שלב, ומעביר את שאר הסיגנלים לשלבים הבאים
​צנרור הcontroller של ספרתיות.png

סכנות בצנרור(HazardsHazardsHazards)

השימוש בצ