الآلات الافتراضية ووحدات التحكم الدقيقة

عند تطوير أجهزة مختلفة ، غالبًا ما تحصل على مشكلة: يتم تكرار الخوارزمية من جهاز إلى جهاز في أماكن ، والأجهزة نفسها مختلفة تمامًا. لدي ثلاثة أجهزة قيد التطوير تكرر في بعض الأماكن وظائف بعضها البعض ، وهي تستخدم ثلاثة معالجات مختلفة (ثلاث بنى مختلفة) ، ولكن هناك خوارزمية واحدة فقط. من أجل توحيد كل شيء بطريقة أو بأخرى ، تم التخطيط لكتابة آلة افتراضية بسيطة.



بشكل عام ، نظرت إلى الرمز الفرعي لـ Java و Lua وأجهزة أخرى ، لكنني لم أرغب حقًا في إعادة كتابة جميع الأمتعة المتاحة بلغة أخرى. لذلك قررنا اللغة - C. على الرغم من أن Java أو Lua لا تزال تبدو جذابة. [1] [2] [3] [4].

المعيار التالي كان المترجم. في مشاريعي غالبًا ما أستخدم "مكتوب بواسطة الطلاب لملفات تعريف الارتباط GCC (c) anonymus". أولئك. إذا كنت تصف الهندسة المعمارية الخاصة بك ، فسيتعين عليك التوصل إلى مجموعة كاملة من دول مجلس التعاون الخليجي (مترجم ، رابط ، إلخ).

نظرًا لأنني شخص كسول ، فقد كنت أبحث عن أصغر بنية ممكنة بدعم دول مجلس التعاون الخليجي. وأصبح MSP430.

وصف قصير


MSP430 هي بنية بسيطة للغاية. لديها فقط 27 تعليمات [5] وتقريبا أي عنونة.

بدأ بناء الآلة الافتراضية مع سياق المعالج. سياق المعالج في أنظمة التشغيل عبارة عن بنية تصف حالة المعالج بشكل كامل. ويتم وصف حالة هذا المعالج الظاهري من خلال ما يلي:

  • الفريق الحالي
  • يسجل
  • حالة اختيارية لسجلات المقاطعة
  • محتويات اختيارية لذاكرة الوصول العشوائي وذاكرة القراءة فقط

سجلات MSP430 هي 16. من بين 16 سجلًا ، يتم استخدام السجلات الأربعة الأولى كسجلات نظام. لنفترض أن السجل الفارغ مسؤول عن المؤشر الحالي للأمر الذي يتم تنفيذه من مساحة العنوان (عداد الأوامر).

يمكنك قراءة المزيد حول التسجيلات في دليل المستخدم الأصلي msp430x1xxx [6]. بالإضافة إلى السجلات ، هناك أيضًا محتويات مساحة العنوان - RAM ، ROM. ولكن نظرًا لأنه من السهل الاحتفاظ بـ "الجهاز المضيف" (الجهاز الذي ينفذ رمز الجهاز الظاهري) في ذاكرة الجهاز الظاهري ، فليس هناك معنى - بشكل متكرر - يتم استخدام رد الاتصال.

يتيح لك هذا الحل تنفيذ برامج "أعسر تمامًا" على معالجات بهندسة Harvard (اقرأ AVR [7] [8]) ، مع أخذ البرنامج من مصادر خارجية (على سبيل المثال ، ذاكرة i2c أو بطاقة SD).

أيضا في سياق المعالج هو وصف سجلات المقاطعة (SFRs). يتم وصف نظام مقاطعة MSP430 بأكبر قدر من الدقة في [6] ، الفقرة 2.2.
ولكن في الجهاز الافتراضي الموصوف ، انتقلت قليلاً عن الأصل. في المعالج الأصلي ، توجد إشارات المقاطعة في السجلات الطرفية. في هذه الحالة ، يتم وصف المقاطعات في سجلات SFR.

يتم وصف محيط المعالج بنفس الطريقة ، عبر رد الاتصال ، مما يسمح لك بإنشاء الأجهزة الطرفية الخاصة بك حسب الرغبة.

عنصر المعالج التالي هو معدد الأوامر. يؤدي معدد الأوامر وظيفة منفصلة. يحدد معدد الإرسال الأمر نفسه من كلمة الأمر ، ويعالج المصدر والمتلقي ، وينفذ إجراء الأمر المحدد.

تصف الوظائف المنفصلة عنونة المصدر (SRC) والمستقبل.

كيفية استخدامها


examples [9] :
  • STM8 IAR
  • STM8 SDCC
  • STM32 Keil armcc
  • AVR GCC


Cpu.h .

:

  • RAM_USE_CALLBACKS — , (callbacks) . RAM ( cpu.ram_read, cpu.ram_write)
  • ROM_USE_CALLBACKS — ROM ( cpu.rom_read)
  • IO_USE_CALLBACKS — ( cpu.io_read, cpu.io_write), 0 msp430_io cpu.c
  • RAM_SIZE — (RAM), ,
  • ROM_SIZE - حجم ROM (ROM) ، يتم إعادة حساب عنوان البداية تلقائيًا استنادًا إلى هذه المعلمة
  • IRQ_USE - يشير إلى ما إذا كان سيتم استخدام المقاطعات ؛ إذا كان 1 ، يتم تمكين المقاطعات
  • HOST_ENDIANESS - يشير إلى ترتيب البايت لوحدة تحكم المضيف (جهاز التحكم الذي يقوم بتشغيل الجهاز الظاهري). إن البنى AVR و X86 و STM32 ذات نهاية صغيرة ، و STM8 ذات نهاية كبيرة
  • DEBUG_ON - يشير إلى ما إذا كان سيتم استخدام التصحيح. يتم التصحيح عن طريق fprintf - stderr


يبدأ استخدام المكتبة بربط cpu.c و cpu.h بالمشروع.

#include "cpu.h"

التالي هو إعلان سياق المعالج. بناءً على استخدام معلمات * _USE_CALLBACKS ، سيتم تغيير رمز تعريف السياق.

للجميع * _USE_CALLBACKS = 1 تعريفات سياق المعالج ستبدو كما يلي:

msp430_context_t cpu_context =
    {
        .ram_read_cb = ram_read,
        .ram_write_cb = ram_write,
        .rom_read_cb = rom_read,
        .io_read_cb = io_read,
        .io_write_cb = io_write
    };


حيث تقبل متغيرات * _cb مؤشرات الدالة (انظر الأمثلة).

بالمقابل ، بالنسبة إلى * _USE_CALLBACKS = 0 ، ستبدو الإعلانات كما يلي:

msp430_context_t cpu_context =
    {
         .rom = { /* hex program */ },
    };

التالي هو تهيئة السياق من خلال الوظيفة:

msp430_init(&cpu_context);

وتنفيذ تعليمات واحدة في كل مرة من خلال وظيفة:

while(1)
    msp430_cpu(&cpu_context);

تبدو الاستدعاءات للعمل مع مساحة العنوان كما يلي:

uint16_t io_read(uint16_t address);
void io_write(uint16_t address,uint16_t data);

uint8_t ram_read(uint16_t address);
void ram_write(uint16_t address,uint8_t data);

uint8_t rom_read(uint16_t address);

يتم إرسال عناوين IO بالنسبة إلى مساحة العنوان 0 (على سبيل المثال ، إذا وصل برنامج الجهاز الظاهري إلى P1IN ، الذي تم تعيينه للعنوان 0x20 ، فسيتم تمرير العنوان 0x20 إلى الوظيفة).

على العكس من ذلك ، يتم إرسال عناوين RAM و ROM نسبةً إلى نقاط البداية (على سبيل المثال ، عند الوصول إلى العنوان 0xfc06 وبدء ROM في 0xfc00 ، سيتم تمرير العنوان 0x0006 إلى الوظيفة. أي أن العنوان من 0 إلى RAM_SIZE ، 0 - ROM_SIZE)

يسمح هذا باستخدام الذاكرة الخارجية ، على سبيل المثال I2C (الذي يبطئ المعالج بالفعل).

كيف تكمل


. , . (, Dadd — ( )). 100% .

, -, - .

bitbucket.org [9].

, - .

[1] dmitry.gr/index.php?r=05.Projects&proj=12.%20uJ%20-%20a%20micro%20JVM
[2] www.harbaum.org/till/nanovm/index.shtml
[3] www.eluaproject.net
[4] code.google.com/p/picoc
[5] ru.wikipedia.org/wiki/MSP430
[6] www.ti.com/lit/ug/slau049f/slau049f.pdf
[7] ru.wikipedia.org/wiki/%D0%93%D0%B0%D1%80%D0%B2%D0%B0%D1%80%D0%B4%D1%81%D0%BA%D0%B0%D1%8F_%D0%B0%D1%80%D1%85%D0%B8%D1%82%D0%B5%D0%BA%D1%82%D1%83%D1%80%D0%B0
[8] ru.wikipedia.org/wiki/AVR
[9] bitbucket.org/intl/msp430_vm

Source: https://habr.com/ru/post/ar385009/


All Articles