
مساء الخير اليوم أريد أن أخبرك كيف تكتب برنامجًا بسيطًا يعمل على ARM Cortex-M3 ويطبع "Hello، World!". سنحاول أن نحدد في الخطوات الحد الأدنى الضروري الذي نحتاجه لذلك. سنعمل على محاكي QEMU. لذلك ، يمكن لأي شخص التكاثر ، حتى لو لم يكن لديه قطعة من الحديد في متناول اليد.
لذا دعنا نذهب!
يدعم محاكي QEMU قلب Cortex-M3 ويحاكي منصة Stellaris LM3S811 من Texas Instruments بناءً على ذلك. سنعمل على هذه المنصة. نحن بحاجة إلى سلسلة أدوات arm-none-eabi- (يمكنك تنزيلها
هنا ). بعد ذلك ، نحتاج إلى كتابة المنطق الرئيسي لبرنامجنا ، رمز البدء ، والذي سينقل التحكم إلى البرنامج ، والبرنامج النصي للرابط.
على مقال
جيد بالفعل
مقالات جيدة حول كيفية وميض الصمام الثنائي على قطعة من الحديد من الصفر. لذلك ، لن أتطرق هنا إلى ما وكيف تعمل ، ولكني سأقدم فقط الحد الأدنى من مجموعة المعرفة الضرورية اللازمة للبدء.
عالم الترحيب الخاص بنا في ملف test.c:
static volatile unsigned int * const UART_DR = (unsigned int *)0x4000c000; static void uart_print(const char *s) { while (*s != '\0') { *UART_DR = *s; s++; } } void c_entry(void) { uart_print("Hello, World!\n"); while (1) ; }
يتم أخذ هذا العنوان 0x4000c000 من الوثائق ، ويوجد سجل DR صفر صفر.
لن نشارك في إعداد UART (هذا يجب القيام به على الأجهزة) ، لكننا سنحاول وضع الرموز فيه مباشرة على الفور.
الآن ، نحن بحاجة إلى نقل التحكم إلى حد ما إلى وظيفتنا مع _entry في ملف test.c. للقيام بذلك ، قم بإنشاء الكود التالي (ملف startup.S) ، ثم ضعه في صورة ELF النهائية في البداية.
.type start, %function .word stack_top .word start .global start start: ldr r1, =c_entry bx r1
يجب أن تكون الكلمة الأولى عند 0x0 مؤشرًا أعلى المكدس (SP). عند 0x4 يوجد جهاز كمبيوتر ، مثل SP ، يتم تحميله في السجلات. لاحظ أن البداية يتم الإعلان عنها بدقة كدالة ، وليس كعلامة لأنه يتم تنفيذ كود Cortex-M في وضع الإبهام (هذه مجموعة مبسطة من أوامر ARM) ، ومن المطلوب أن تكون عناوين الوظائف في ناقلات المقاطعة في النموذج (العنوان | 0x1) - أي يجب أن يكون الجزء الأخير من العنوان 1.
بعد ذلك ، تقوم وظيفة البداية بتحميل عنوان وظيفة c_entry () الخاصة بنا من ملف test.c وتمرير التحكم من خلال "bx r1" هناك.
يبقى فقط لربط برنامجنا بنجاح. للقيام بذلك ، تحتاج إلى تعيين بطاقة ذاكرة متحكمنا. في الوثائق ، يمكنك العثور على عناوين وأحجام ذاكرة الفلاش (ROM) وذاكرة الوصول العشوائي (RAM). هنا هو البرنامج النصي link.ld رابط:
SECTIONS { . = 0x0; .text : { startup.o(.text) test.o(.text) } . = 0x20000000; .data : { *(.data) } .bss : { *(.bss) } . = ALIGN(8); . = . + 0x1000; stack_top = .; }
من المهم الانتباه إلى العناوين. "." في البرنامج النصي linker يشير إلى الموضع الحالي. نضع قسم .text في بداية ROM (العنوان 0x0) ، بعد الترتيب - يبدأ startup.o (.text) أولاً. بعد ذلك ، انتقل إلى ذاكرة الوصول العشوائي (. = 0x20000000 ؛) وأدخل البيانات (البيانات العالمية الأولية) و bss (البيانات العالمية غير المهيأة). أدناه نرى ALIGN (8) - ARM يتطلب محاذاة SP (مؤشر المكدس) بمقدار 8. نظرًا لأن المكدس ينمو ، فإن تخصيص مساحة تحت المكدس هو مجرد إضافة. " =. + 0x1000 ". نحن نعلم برنامجنا جيدًا ، لذا فإن مكدس 4 كيلو بايت يكفي بهامش كبير.
هذا كل شيء ، يبقى تجميع كل شيء. أحمل build.sh:
كل شيء هنا يجب أن يُفهم بشكل أو بآخر ، باستثناء علم العلامة التجارية. في هذه الحالة ، لا يتعين عليك إضافتها (يمكنك التحقق منها) ، ولكن نظرًا لأننا نقوم بإعداد صورة بارميتال من الصفر ، فمن الأفضل إخبار المترجم بحيث لا ينتبه إلى وظائف مثل main ().
نتيجة لذلك ، حصلنا على اختبار ملف ELF. قم بتشغيله على QEMU:
$ qemu-system-arm -M lm3s811evb -kernel test.elf -nographic Hello, World!
يعمل.
بالطبع ، هذه دراسة حالة مصممة لفهم ما يحدث. إذا كنت بحاجة إلى وظائف أكثر فائدة ، فيجب عليك استخدام الأشياء الجاهزة. لقد أضفنا دعمًا لهذه المنصة في
Embox . يسمى هذا القالب platform / stellaris / lm3s811evb. لذلك ، إذا أراد شخص ما محاولة تشغيل شيء أكثر خطورة قليلاً (وحدة التحكم ، المؤقت ، المقاطعات) ، فيمكنك حينئذٍ التجميع والمحاولة. في هذه الحالة ، أكرر ، لا تحتاج إلى لوحة أجهزة.
وأولئك الذين ما زالوا لا يملكون ما يكفي من المحاكيات ، أو الذين يريدون أن
يسألونا أسئلة ويلعبوا بقطع الحديد ، سننتظر هذا السبت والأحد في مهرجان تكنولوجيا المعلومات
techtrain.ru في سانت بطرسبرغ. سيكون لدينا قطع مختلفة من الحديد على الحامل ، وفي المنطقة التجريبية سنحاول معرفة كيفية برمجتها.