ฉันเห็นปัญหาที่อาจเกิดขึ้นกับส่วนที่สำคัญเหล่านั้น มีคำเตือนและแนวทางแก้ไขสำหรับสิ่งเหล่านี้ทั้งหมด แต่โดยสรุป
- ไม่มีสิ่งใดที่ทำให้คอมไพเลอร์ย้ายโค้ดข้ามมาโครเหล่านี้เพื่อเพิ่มประสิทธิภาพหรือเหตุผลอื่น ๆ
- พวกเขาบันทึกและกู้คืนบางส่วนของหน่วยประมวลผลสถานะคอมไพเลอร์คาดว่าแอสเซมบลีแบบอินไลน์จะปล่อยให้อยู่คนเดียว (เว้นแต่จะมีการบอกเป็นอย่างอื่น)
- ไม่มีสิ่งใดขัดขวางการขัดจังหวะไม่ให้เกิดขึ้นระหว่างการเรียงลำดับและการเปลี่ยนสถานะระหว่างเมื่ออ่านและเขียน
ปิดแรกคุณแน่นอนต้องมีอุปสรรคในหน่วยความจำของคอมไพเลอร์ การดำเนินการเหล่านี้เป็น GCC clobbers โดยทั่วไปนี่เป็นวิธีที่จะบอกคอมไพเลอร์ "ไม่คุณไม่สามารถย้ายการเข้าถึงหน่วยความจำผ่านแอสเซมบลีอินไลน์ชิ้นนี้เพราะมันอาจส่งผลต่อผลลัพธ์ของการเข้าถึงหน่วยความจำ" โดยเฉพาะคุณต้องใช้ทั้งสอง"memory"
และ"cc"
clobbers ทั้งในแมโครเริ่มต้นและสิ้นสุด สิ่งเหล่านี้จะป้องกันสิ่งอื่น ๆ (เช่นการเรียกใช้ฟังก์ชัน) จากการจัดลำดับใหม่สัมพันธ์กับชุดประกอบแบบอินไลน์เช่นกันเพราะคอมไพเลอร์รู้ว่าพวกเขาอาจมีการเข้าถึงหน่วยความจำ ฉันเห็น GCC สำหรับสถานะการพัก ARM ในรหัสเงื่อนไขลงทะเบียนในชุดประกอบแบบอินไลน์ด้วย"memory"
clobbers ดังนั้นคุณจึงจำเป็นต้องใช้"cc"
clobber
ประการที่สองส่วนสำคัญเหล่านี้กำลังบันทึกและกู้คืนมากกว่าการเปิดใช้อินเทอร์รัปต์ โดยเฉพาะพวกเขากำลังบันทึกและกู้คืนCPSRส่วนใหญ่(การลงทะเบียนสถานะโปรแกรมปัจจุบัน) (ลิงก์สำหรับ Cortex-R4 เพราะฉันไม่สามารถหาไดอะแกรมที่ดีสำหรับ A9 ได้ แต่ควรเหมือนกัน) มีข้อ จำกัด ที่ลึกซึ้งซึ่งชิ้นส่วนของรัฐสามารถแก้ไขได้จริง แต่มีความจำเป็นมากกว่าที่นี่
เหนือสิ่งอื่นใดซึ่งรวมถึงรหัสเงื่อนไข (ซึ่งcmp
จัดเก็บผลลัพธ์ของคำแนะนำเช่นนั้นคำสั่งตามเงื่อนไขที่ตามมาสามารถกระทำกับผลลัพธ์ได้) คอมไพเลอร์จะสับสนกับสิ่งนี้อย่างแน่นอน วิธีนี้สามารถแก้ไขได้อย่างง่ายดายโดยใช้"cc"
Clobber ดังกล่าวข้างต้น อย่างไรก็ตามการทำเช่นนี้จะทำให้โค้ดล้มเหลวทุกครั้งดังนั้นจึงไม่เหมือนกับสิ่งที่คุณเห็นปัญหา แม้ว่าจะมีระเบิดเวลาฟ้องในการปรับเปลี่ยนรหัสอื่น ๆ แบบสุ่มอาจทำให้คอมไพเลอร์ทำบางสิ่งที่แตกต่างกันเล็กน้อยซึ่งจะถูกทำลายโดยสิ่งนี้
นอกจากนี้ยังจะพยายามที่จะบันทึก / เรียกคืนบิตไอทีซึ่งจะใช้ในการดำเนินการดำเนินการตามเงื่อนไขที่นิ้วหัวแม่มือ โปรดทราบว่าหากคุณไม่เคยใช้รหัส Thumb มันไม่สำคัญเลย ฉันไม่เคยคิดเลยว่าชุดประกอบแบบอินไลน์ของ GCC เกี่ยวข้องกับบิตไอทีอย่างไรนอกเหนือจากการสรุปไม่ได้หมายความว่าคอมไพเลอร์จะต้องไม่ใส่ชุดประกอบแบบอินไลน์ในบล็อกไอทีและคาดว่าการชุมนุมจะสิ้นสุดนอกบล็อกไอที ฉันไม่เคยเห็น GCC สร้างรหัสที่ละเมิดสมมติฐานเหล่านี้และฉันได้ทำชุดอินไลน์ที่ซับซ้อนด้วยการเพิ่มประสิทธิภาพอย่างหนักดังนั้นฉันจึงมั่นใจว่าพวกเขามีเหตุผล ซึ่งหมายความว่าอาจไม่ได้พยายามเปลี่ยนบิตไอทีซึ่งในกรณีนี้ทุกอย่างเรียบร้อย ความพยายามในการปรับเปลี่ยนบิตเหล่านี้จัดอยู่ในประเภท "ไม่แน่นอนทางสถาปัตยกรรม"ดังนั้นมันสามารถทำสิ่งเลวร้ายทุกประเภท แต่อาจจะไม่ทำอะไรเลย
ประเภทสุดท้ายของบิตที่จะถูกบันทึก / กู้คืน (นอกเหนือจากที่ปิดการใช้งานจริง) เป็นบิตโหมด สิ่งเหล่านี้อาจไม่เปลี่ยนแปลงดังนั้นจึงอาจไม่สำคัญ แต่ถ้าคุณมีรหัสใด ๆ ที่เปลี่ยนโหมดโดยเจตนาส่วนที่ถูกขัดจังหวะอาจทำให้เกิดปัญหาได้ การเปลี่ยนระหว่างสิทธิพิเศษและโหมดผู้ใช้เป็นกรณีเดียวที่ฉันคาดหวัง
ประการที่สามมีอะไรป้องกันการขัดจังหวะจากการเปลี่ยนชิ้นส่วนอื่น ๆ ของ CPSR ระหว่างMRS
และในMSR
ARM_INT_LOCK
การเปลี่ยนแปลงใด ๆ ดังกล่าวอาจถูกเขียนทับ ในระบบที่เหมาะสมที่สุดการขัดจังหวะแบบอะซิงโครนัสจะไม่เปลี่ยนสถานะของรหัสที่พวกเขากำลังขัดจังหวะ (รวมถึง CPSR) หากพวกเขาทำมันจะยากมากที่จะให้เหตุผลเกี่ยวกับรหัสที่จะทำ อย่างไรก็ตามเป็นไปได้ (การเปลี่ยนบิตการปิดใช้งาน FIQ ดูเหมือนจะเป็นไปได้มากที่สุดสำหรับฉัน) ดังนั้นคุณควรพิจารณาว่าระบบของคุณทำสิ่งนี้หรือไม่
นี่คือวิธีที่ฉันจะใช้สิ่งเหล่านี้ในวิธีที่จะจัดการกับปัญหาที่อาจเกิดขึ้นทั้งหมดที่ฉันชี้ให้เห็น:
#define ARM_INT_KEY_TYPE unsigned int
#define ARM_INT_LOCK(key_) \
asm volatile(\
"mrs %[key], cpsr\n\t"\
"ands %[key], %[key], #0xC0\n\t"\
"cpsid if\n\t" : [key]"=r"(key_) :: "memory", "cc" );
#define ARM_INT_UNLOCK(key_) asm volatile (\
"tst %[key], #0x40\n\t"\
"beq 0f\n\t"\
"cpsie f\n\t"\
"0: tst %[key], #0x80\n\t"\
"beq 1f\n\t"\
"cpsie i\n\t"
"1:\n\t" :: [key]"r" (key_) : "memory", "cc")
ให้แน่ใจว่าจะรวบรวมด้วย-mcpu=cortex-a9
เพราะอย่างน้อยบางรุ่น GCC (เช่นเหมือง) เริ่มต้นซีพียู ARM เก่าซึ่งไม่สนับสนุนและcpsie
cpsid
ผมใช้ands
แทนเพียงand
ในARM_INT_LOCK
จึงเป็นคำแนะนำ 16 บิตถ้าเรื่องนี้ถูกนำมาใช้ในรหัสหัวแม่มือ การ"cc"
อุดตันนั้นเป็นสิ่งจำเป็นต่อไปดังนั้นจึงเป็นประโยชน์อย่างมากต่อประสิทธิภาพ / ขนาดโค้ด
0
และ1
เป็นฉลากท้องถิ่นสำหรับการอ้างอิง
สิ่งเหล่านี้ควรใช้งานได้ในวิธีเดียวกับเวอร์ชั่นของคุณ ARM_INT_LOCK
เป็นเพียงเป็นไปอย่างรวดเร็ว / ขนาดเล็กเป็นหนึ่งในต้นฉบับของคุณ น่าเสียดายที่ฉันไม่สามารถหาวิธีที่จะทำARM_INT_UNLOCK
อย่างปลอดภัยได้ทุกที่ใกล้กับคำแนะนำเล็กน้อย
หากระบบของคุณมีข้อ จำกัด เมื่อ IRQ และ FIQ ถูกปิดการใช้งานสิ่งนี้อาจทำให้ง่ายขึ้น ตัวอย่างเช่นหากพวกเขาปิดการใช้งานด้วยกันเสมอคุณสามารถรวมเป็นหนึ่งcbz
+ cpsie if
เช่นนี้:
#define ARM_INT_UNLOCK(key_) asm volatile (\
"cbz %[key], 0f\n\t"\
"cpsie if\n\t"\
"0:\n\t" :: [key]"r" (key_) : "memory", "cc")
อีกทางเลือกหนึ่งถ้าคุณไม่สนใจ FIQ เลยก็เหมือนกับว่าคุณแค่เปิด / ปิดการใช้งานทั้งหมด
ถ้าคุณรู้ว่าไม่มีอะไรอื่นที่เคยมีการเปลี่ยนแปลงใด ๆ ของบิตของรัฐอื่น ๆ ใน CPSR ระหว่างการล็อคและปลดล็อคแล้วคุณยังสามารถใช้ดำเนินการกับบางสิ่งบางอย่างคล้ายกับรหัสเดิมของคุณยกเว้นมีทั้ง"memory"
และ"cc"
clobbers ทั้งในARM_INT_LOCK
และARM_INT_UNLOCK