سؤال

أنا أحاول أن أداء أقل من 32 بت قراءة أكثر من ناقل PCI إلى VME-جسر رقاقة (التندرا الكون الثاني) ، والتي سوف تذهب على VME حافلة التقطت من قبل الهدف.

الهدف VME التطبيق لا يقبل إلا D32 (بيانات العرض قراءة من 32bits) وسيتم تجاهل أي شيء آخر.

إذا كنت تستخدم قليلا مجال بنية تعيين أكثر من VME نافذة (nmap كنت في الذاكرة الرئيسية) أستطيع قراءة بعض الحقول >24 بت, ولكن أي شيء أقل من فشل.أي :-

struct works {
    unsigned int a:24;
};

struct fails {
    unsigned int a:1;
    unsigned int b:1;
    unsigned int c:1;
};

struct main {
    works work;
    fails fail;
}
volatile *reg = function_that_creates_and_maps_the_vme_windows_returns_address()

هذا يدل على أن البنية يعمل هو برنامج 32bit لكن قراءة عن طريق فشل البنية من a على سبيل المثال reg->تفشل.a هو الحصول على الاعتبار إلى س بت قراءة.(حيث X قد تكون 16 أو 8؟)

وبالتالي فإن الأسئلة هي :
أ) أين هو هذا تحجيمها إلى أسفل ؟ ومترجم ؟ OS ؟ أو التندرا الشريحة ؟
ب) ما هو الحجم الفعلي من عملية القراءة بها ؟

البحث أساسا أنا أريد أن يستبعد كل رقاقة.وثائق على شبكة الإنترنت ، ولكن إذا ثبت أن البيانات عرض وطلب على ناقل PCI 32bits ثم المشكلة يمكن إلقاء اللوم على التندرا رقاقة!

تحرير:-
ملموسة سبيل المثال ، القانون:-

struct SVersion
{
    unsigned title         : 8;
    unsigned pecversion    : 8;
    unsigned majorversion  : 8;
    unsigned minorversion  : 8;
} Version;

حتى الآن لقد تغيرت إلى هذا :-

union UPECVersion
{
    struct SVersion
    {
        unsigned title         : 8;
        unsigned pecversion    : 8;
        unsigned majorversion  : 8;
        unsigned minorversion  : 8;
    } Version;
    unsigned int dummy;
};

والقاعدة الرئيسية البنية :-

typedef struct SEPUMap
{
    ...
    ...
    UPECVersion PECVersion;

};

لذلك أنا لا تزال بحاجة الى تغيير كل ما عندي من الأساس رمز

// perform dummy 32bit read
pEpuMap->PECVersion.dummy;

// get the bits out
x = pEpuMap->PECVersion.Version.minorversion;

و كيف أعرف إذا كان الثاني قراءة متعود القيام به في الواقع قراءة حقيقية مرة أخرى ، كما بلدي الأصلي رمز ؟ (بدلا من استخدام بالفعل قراءة البتات عبر الاتحاد!)

هل كانت مفيدة؟

المحلول

كمثال، لدى Linux Kernel الوظائف المضمنة التي تتعامل بشكل صريح بقراءة IO المعينة بالذاكرة والكتابة. في NEWER KERNELS، إنها غلاف كاسرو كبير يتلخص إلى مجموعة مضمنة movl التعليمات، لكنها النواة القديمة التي تم تعريفها مثل هذا:

#define readl(addr) (*(volatile unsigned int *) (addr))
#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))

نصائح أخرى

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

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

خيار واحد هو القوة مترجم إلى استخدام محاذاة مختلفة الإعدادات.الخيارات للقيام بذلك تختلف من مترجم مترجم, لذلك عليك التحقق من الوثائق.انها عادة ما تكون #pragma من نوع ما.على بعض المجمعين (Microsoft المجمعين ، على سبيل المثال) انه من الممكن تغيير الذاكرة المحاذاة فقط صغير جدا المقطع من التعليمات البرمجية.على سبيل المثال (في VC++):

#pragma pack(push)      // save the current alignment
#pragma pack(1)         // set the alignment to one byte
// Define variables that are alignment sensitive
#pragma pack(pop)       // restore the alignment

وثمة خيار آخر هو تحديد المتغيرات الخاصة بك بطرق أخرى.الجوهرية أنواع لا تغيير على أساس التوافق ، لذا بدلا من 24 بت bitfield نهج آخر هو تعريف متغير صفيف من البايت.

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

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

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

أنا أتساءل عن قيمة sizeof(struct fails). وبعد هل هو 1؟ في هذه الحالة، إذا قمت بإجراء قراءة من قبل dereferenceing مؤشر إلى struct fails, ، يبدو صحيحا لإصدار D8 اقرأ على حافلة VME.

يمكنك محاولة إضافة حقل unsigned int unused:29; لك struct fails.

حجم أ struct لا يساوي مجموع حجم حقوله، بما في ذلك حقول بت. يسمح بالمجمعات المجامعة، من خلال مواصفات لغة C و C ++، لإدراج الحشو بين الحقول في struct. وبعد غالبا ما يتم إدراج الحشو لأغراض المحاذاة.

الطريقة الشائعة في برمجة الأنظمة المضمنة هي قراءة البيانات ك عدد صحيح غير موقعة ثم استخدم اخفاء بعض الشيء لاسترداد البتات المثيرة للاهتمام. هذا يرجع إلى القاعدة المذكورة أعلاه التي ذكرتها وحقيقة أنه لا توجد معلمة مترجم قياسية لحقول "التعبئة" في هيكل.

أقترح إنشاء كائن ( class أو struct) للتفاعل مع الأجهزة. دع الكائن اقرأ البيانات، ثم استخراج البتات bool أفراد. هذا يضع التنفيذ على مقربة من الأجهزة. يجب ألا يهتم البرنامج المتبقي كيف يتم تنفيذ البتات.

عند تحديد المواقف الميدانية بت / تسمى الثوابت، أقترح هذا التنسيق:

#define VALUE (1 << موقف بت)
// OR
const unsigned int VALUE = 1 << موقف بت;

هذا التنسيق أكثر قابلية للقراءة ولديه التحويل البرمجي أدى الحساب. يحدث حساب أثناء التجميع وليس له أي تأثير أثناء وقت التشغيل.

إيان - إذا كنت ترغب في التأكد من حجم الأشياء التي تقرأها / كتابتها، أقترح عدم استخدام الهياكل مثل هذا للقيام بذلك - فمن الممكن أن Sizeof of the Fails Form هو فقط 1 بايت - المحول البرمجي مجاني لتحديد ما يجب أن يستند إلى تحسينات على التحسينات، أود أن أقترح القراءة / الكتابة بشكل صريح باستخدام الأشياء أو عموما التي تحتاجها إلى ضمان أحجام وأداء شيء آخر مثل التحويل إلى الاتحاد / الهيكل حيث ليس لديك تلك القيود.

هذا هو المحول البرمجي الذي يقرر ما يقرأ حجم القراءة. لإجبار قراءة 32 بت، يمكنك استخدام union:

union dev_word {
    struct dev_reg {
        unsigned int a:1;
        unsigned int b:1;
        unsigned int c:1;
    } fail;
    uint32_t dummy;
};

volatile union dev_word *vme_map_window();

إذا كانت قراءة الاتحاد من خلال مؤشر مؤهل متقلب لا يكفي لإجبار قراءة الاتحاد بأكمله (أعتقد أنه سيكون - ولكن يمكن أن يكون ذلك يعتمد على مترجم)، فيمكنك استخدام وظيفة لتوفير عدم التنذير المطلوب في

volatile union dev_word *real_reg; /* Initialised with vme_map_window() */

union dev_word * const *reg_func(void)
{
    static union dev_word local_copy;
    static union dev_word * const static_ptr = &local_copy;

    local_copy = *real_reg;
    return &static_ptr;
}

#define reg (*reg_func())

... ثم (للتوافق مع التعليمات البرمجية الموجودة) يتم الوصول إليك على النحو التالي:

reg->fail.a

الطريقة الموصوفة في وقت سابق من استخدام علم دول مجلس التعاون الخليجي - في بيتفليلدز، تحديد متغيرات Bitfield كما يعمل U32 متقلبة، ولكن يجب أن يكون عدد البتات الإجمالي المحدد أكبر من 16.

علي سبيل المثال:

typedef     union{
    vu32    Word;
    struct{
        vu32    LATENCY     :3;
        vu32    HLFCYA      :1;
        vu32    PRFTBE      :1;
        vu32    PRFTBS      :1;  
    };
}tFlashACR;
.
tFLASH* const pFLASH    =   (tFLASH*)FLASH_BASE;
#define FLASH_LATENCY       pFLASH->ACR.LATENCY
.
FLASH_LATENCY = Latency;

يسبب دول مجلس التعاون الخليجي لتوليد التعليمات البرمجية

.
ldrb r1, [r3, #0]
.

وهو قراءة بايت. ومع ذلك، تغيير typedef إلى

typedef     union{
    vu32    Word;
    struct{
        vu32    LATENCY     :3;
        vu32    HLFCYA      :1;
        vu32    PRFTBE      :1;
        vu32    PRFTBS      :1;
        vu32                :2;

        vu32    DUMMY1      :8;

        vu32    DUMMY2      :8;
    };
}tFlashACR;

يغير التعليمات البرمجية الناتجة

.
ldr r3, [r2, #0]
.

أعتقد أن الحل الوحيد هو
1) تحرير / إنشاء بنية الرئيسية كلها كل 32bit Ints (يتوقت غير موقعة)
2) الحفاظ على بلدي البت البت البت
3) كل الوصول أحتاج،
3.1) علي قراءة عضو الهيكل ككلمة 32bit، وألقته في بنية مجال بت،
3.2) اقرأ عنصر بت الحقل الذي أحتاجه. (وللكتابة، قم بتعيين حقل البت هذا، واكتب الكلمة مرة أخرى!)

(1) وهو ما هو نفسه، لأنه ثم أفقد الأنواع الجوهرية التي تكون فيها كل عضو في بنية "Main / sepumap".

حل النهاية: -
بدلا من :-

printf("FirmwareVersionMinor: 0x%x\n", pEpuMap->PECVersion);

هذه :-

SPECVersion ver = *(SPECVersion*)&pEpuMap->PECVersion;

printf("FirmwareVersionMinor: 0x%x\n", ver.minorversion);

مشكلة فقط لدي هو WRTITTITE! (يكتب الآن قراءة / تعديل / يكتب!)

// Read - Get current
_HVPSUControl temp = *(_HVPSUControl*)&pEpuMap->HVPSUControl;

// Modify - set to new value
temp.OperationalRequestPort = true;

// Write
volatile unsigned int *addr = reinterpret_cast<volatile unsigned int*>(&pEpuMap->HVPSUControl);

*addr = *reinterpret_cast<volatile unsigned int*>(&temp);

فقط تضطر إلى مرتبة تلك الكود في طريقة!

#define writel(addr, data) ( *(volatile unsigned long*)(&addr) = (*(volatile unsigned long*)(&data)) )

كان لدي نفس المشكلة في الذراع باستخدام مترجم GCC، حيث الكتابة في الذاكرة فقط من خلال البايت بدلا من كلمة 32 بت.

الحل هو تحديد حقول بت باستخدام uint32_t (أو الحجم المطلوب للكتابة):

union {
    volatile uint32_t XY;
    struct {
        volatile uint32_t XY_A : 4;
        volatile uint32_t XY_B : 12;
    };
};

ولكن أثناء تجميع تحتاج إلى إضافة إلى GCC أو G ++ هذه المعلمة:

-fstrict-volatile-bitfields

أكثر في وثائق دول مجلس التعاون الخليجي.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top