c बिट अच्छा प्रथाओं में हेरफेर




standards bit (6)

एक शुरुआती सी प्रोग्रामर के रूप में, मैं सोच रहा हूं, एक डिवाइस में नियंत्रण बिट्स स्थापित करने के लिए सबसे अच्छा आसान पढ़ने और समझने में आसान समाधान क्या होगा। क्या कोई मानक हैं ? नकल करने के लिए कोई उदाहरण कोड? Google ने कोई विश्वसनीय उत्तर नहीं दिया।

उदाहरण के लिए, मेरे पास एक कंट्रोल ब्लॉक मैप है:

पहला तरीका जो मैं देख रहा हूँ वह होगा बस जरूरत बिट्स को सेट करना। यह टिप्पणियों में स्पष्टीकरण का एक गुच्छा की आवश्यकता है और लगता है कि यह सब पेशेवर नहीं है।

DMA_base_ptr[DMA_CONTROL_OFFS] = 0b10001100;

दूसरा तरीका मैं देख रहा हूँ कि थोड़ा सा क्षेत्र बनाना है। मुझे यकीन नहीं है कि यह वही होना चाहिए, जिससे मुझे चिपकना चाहिए, क्योंकि मैंने कभी भी इसका इस तरह से उपयोग नहीं किया था (मेरे द्वारा बताए गए पहले विकल्प के विपरीत)।

struct DMA_control_block_struct
{ 
    unsigned int BYTE:1; 
    unsigned int HW:1; 
    // etc
} DMA_control_block_struct;

क्या विकल्पों में से एक दूसरे से बेहतर है? क्या मेरे पास कोई विकल्प नहीं है?

किसी भी सलाह बहुत सराहना की जाएगी


अन्य उत्तर पहले से ही अधिकांश सामान को कवर कर चुके हैं, लेकिन यह उल्लेख करना सार्थक हो सकता है कि भले ही आप गैर-मानक 0 0b सिंटैक्स का उपयोग न कर 0b , आप 1 नंबर को बिट संख्या द्वारा स्थिति में स्थानांतरित करने के लिए पाली का उपयोग कर सकते हैं, अर्थात:

#define DMA_BYTE  (1U << 0)
#define DMA_HW    (1U << 1)
#define DMA_WORD  (1U << 2)
#define DMA_GO    (1U << 3)
// …

ध्यान दें कि अंतिम संख्या दस्तावेज में "बिट संख्या" कॉलम से कैसे मेल खाती है।

बिट्स सेट करने और साफ़ करने का उपयोग नहीं बदलता:

#define DMA_CONTROL_REG DMA_base_ptr[DMA_CONTROL_OFFS]

DMA_CONTROL_REG |= DMA_HW | DMA_WORD;    // set HW and WORD
DMA_CONTROL_REG &= ~(DMA_BYTE | DMA_GO); // clear BYTE and GO

आप बिट-फील्ड का उपयोग कर सकते हैं, इसके बावजूद कि यहां सभी भय-मुंगेर क्या कह रहे हैं। आपको बस यह जानना होगा कि संकलक (ओं) और सिस्टम एबीआई (ओं) को आपने बिट-फील्ड के "कार्यान्वयन परिभाषित" पहलुओं को परिभाषित करने के लिए अपने कोड को कैसे काम करने का इरादा है। बच्चों को "कार्यान्वयन में परिभाषित" जैसे शब्द बोल्ड करने से डरा नहीं।

हालाँकि, अब तक जिन अन्य लोगों को याद किया गया है, वे विभिन्न पहलू हैं कि मेमोरी-मैप किए गए हार्डवेयर उपकरण कैसे व्यवहार कर सकते हैं, जो C जैसी उच्च-स्तरीय भाषा के साथ व्यवहार करते समय प्रति-सहज हो सकते हैं और अनुकूलन ऐसी भाषाओं की सुविधा प्रदान करते हैं। उदाहरण के लिए, हार्डवेयर रजिस्टर के प्रत्येक पढ़ने या लिखने पर कभी-कभी साइड-इफेक्ट्स हो सकते हैं, भले ही बिट्स को राइट पर नहीं बदला गया हो। इस बीच ऑप्टिमाइज़र यह बताना मुश्किल कर सकता है कि उत्पन्न कोड वास्तव में रजिस्टर के पते पर पढ़ रहा है या लिख ​​रहा है, और तब भी जब रजिस्टर का वर्णन करने वाली सी वस्तु सावधानी से योग्य है, जब I / O को नियंत्रित करने के लिए बहुत सावधानी की आवश्यकता होती है। होता है।

शायद आपको मेमोरी-मैप किए गए हार्डवेयर उपकरणों को सही तरीके से हेरफेर करने के लिए अपने कंपाइलर और सिस्टम द्वारा परिभाषित कुछ विशिष्ट तकनीक का उपयोग करने की आवश्यकता होगी। यह कई एम्बेडेड सिस्टम के लिए मामला है। कुछ मामलों में कंपाइलर और सिस्टम विक्रेता वास्तव में बिट-फील्ड का उपयोग करेंगे, जैसे कुछ मामलों में लिनक्स करता है। मैं पहले आपके संकलक मैनुअल को पढ़ने का सुझाव दूंगा।

आपके द्वारा उद्धृत बिट विवरण तालिका इंटेल एवलॉन डीएमए नियंत्रक कोर के नियंत्रण रजिस्टर के लिए प्रतीत होती है। "रीड / राइट / क्लियर" कॉलम एक संकेत देता है कि किसी विशेष बिट को कैसे पढ़ा या लिखा जाता है। उस डिवाइस के लिए स्थिति रजिस्टर में एक बिट का उदाहरण है जहां शून्य लिखना थोड़ा मूल्य स्पष्ट करेगा, लेकिन हो सकता है कि वह उसी मान को वापस न पढ़े जैसा लिखा गया था - अर्थात रजिस्टर लिखने से डिवाइस में साइड-इफेक्ट हो सकता है। DONE बिट के मूल्य के आधार पर। दिलचस्प है कि वे सॉफ्टवेरसेट बिट को "आरडब्ल्यू" के रूप में दस्तावेज करते हैं, लेकिन फिर रीसेट को ट्रिगर करने के लिए दो बार इसे 1 लिखने के रूप में प्रक्रिया का वर्णन करते हैं, और फिर वे डीएमए सॉफ्टवेयर रीसेट करने पर चेतावनी देते हैं जब डीएमए हस्तांतरण सक्रिय होता है, तो स्थायी बस लॉकअप हो सकता है। (अगली प्रणाली रीसेट होने तक)। SOFTWARERESET बिट को अंतिम उपाय के रूप में छोड़कर नहीं लिखा जाना चाहिए। सी में एक रीसेट का प्रबंधन कुछ सावधानी से कोडिंग करेगा चाहे आप रजिस्टर का वर्णन कैसे करें।

मानकों के अनुसार, अच्छी तरह से आईएसओ / आईईसी ने एक "तकनीकी रिपोर्ट" का उत्पादन किया है, जिसे "आईएसओ / आईईसी टीआर 18037" के रूप में जाना जाता है, उपशीर्षक के साथ "एक्सटेंडेड प्रोसेसर का समर्थन करने के लिए एक्सटेंशन" । यह हार्डवेयर एड्रेसिंग और डिवाइस I / O को प्रबंधित करने के लिए C का उपयोग करने से संबंधित कई मुद्दों पर चर्चा करता है, और विशेष रूप से बिट-मैप किए गए रजिस्टरों के प्रकार के लिए जो आप अपने प्रश्न में उल्लेख करते हैं, यह कई मैक्रोज़ और तकनीकों को शामिल करता है, जिसमें वे शामिल फ़ाइल के माध्यम से उपलब्ध हैं। कॉल करें <iohw.h> । यदि आपका कंपाइलर ऐसी हेडर फ़ाइल प्रदान करता है, तो आप इन मैक्रो का उपयोग करने में सक्षम हो सकते हैं।

टीआर 18037 की ड्राफ्ट प्रतियां उपलब्ध हैं, नवीनतम टीआर 18037 (2007) है , हालांकि यह सूखा पढ़ने के लिए प्रदान करता है। हालाँकि इसमें <iohw.h> का एक उदाहरण कार्यान्वयन है।

शायद वास्तविक दुनिया का एक अच्छा उदाहरण <iohw.h> कार्यान्वयन QNX में है। QNX प्रलेखन एक सभ्य अवलोकन प्रदान करता है (और एक उदाहरण है, हालांकि मैं दृढ़ता से पूर्णांक मानों के लिए enum s का उपयोग करने का सुझाव <iohw.h> , कभी मैक्रोज़ नहीं): QNX <iohw.h>


जब आप चर को उनके मूल्यों को संग्रहीत करने के लिए घोषित करते हैं, तो आपको ज्ञात डिफ़ॉल्ट मान के लिए बिट्स को इनिशियलाइज़ करना सुनिश्चित करना चाहिए। C , जब आप एक वैरिएबल की घोषणा करते हैं तो आप एक पते पर मेमोरी ब्लॉक कर रहे होते हैं और ब्लॉक का आकार इसके प्रकार पर आधारित होता है। यदि आप वैरिएबल को इनिशियलाइज़ नहीं करते हैं तो आप अपरिभाषित / अनपेक्षित व्यवहार का सामना कर सकते हैं क्योंकि वैरिएबल का मान उस ब्लॉक में मेमोरी के मूल्य / स्थिति जो भी आप घोषित किया गया था, उससे प्रभावित होगा। चर को एक डिफ़ॉल्ट मान से प्रारंभ करके, आप इसकी मौजूदा स्थिति की स्मृति को ब्लॉक कर रहे हैं और इसे ज्ञात स्थिति में डाल रहे हैं।

जहाँ तक पठनीयता है, आपको बिट के मूल्यों को संग्रहीत करने के लिए एक बिट फ़ील्ड का उपयोग करना चाहिए। एक बिट फ़ील्ड आपको एक संरचना में बिट्स के मूल्यों को संग्रहीत करने में सक्षम बनाता है। इससे आपको व्यवस्थित करना आसान हो जाता है क्योंकि आप डॉट नोटेशन का उपयोग कर सकते हैं। साथ ही, आपको यह बताने के लिए कि विभिन्न क्षेत्रों को एक सर्वोत्तम अभ्यास के रूप में उपयोग करने के लिए बिट फ़ील्ड की घोषणा पर टिप्पणी करना सुनिश्चित करना चाहिए। हम उम्मीद करते है कि यह आपके सवाल का जवाब दे देगा। आप C प्रोग्रामिंग के साथ शुभकामनाएँ!


आधुनिक सी संकलक तुच्छ इनलाइन कार्यों को ठीक से संभालते हैं - ओवरहेड के बिना। मैं सभी अमूर्त कार्यों को करूंगा, ताकि उपयोगकर्ता को किसी भी बिट या पूर्णांक में हेरफेर करने की आवश्यकता न हो, और कार्यान्वयन विवरण का दुरुपयोग करने की संभावना न हो।

आप निश्चित रूप से स्थिरांक का उपयोग कर सकते हैं और कार्यान्वयन विवरण के लिए कार्य नहीं कर सकते हैं, लेकिन एपीआई कार्य होना चाहिए। यदि आप एक प्राचीन संकलक का उपयोग कर रहे हैं, तो यह फ़ंक्शन के बजाय मैक्रोज़ का उपयोग करने की भी अनुमति देता है।

उदाहरण के लिए:

#include <stdbool.h>
#include <stdint.h>

typedef union DmaBase {
  volatile uint8_t u8[32];
} DmaBase;
static inline DmaBase *const dma1__base(void) { return (void*)0x12340000; }

// instead of DMA_CONTROL_OFFS
static inline volatile uint8_t *dma_CONTROL(DmaBase *base) { return &(base->u8[12]); }
// instead of constants etc
static inline uint8_t dma__BYTE(void) { return 0x01; }

inline bool dma_BYTE(DmaBase *base) { return *dma_CONTROL(base) & dma__BYTE(); }
inline void dma_set_BYTE(DmaBase *base, bool val) {
  if (val) *dma_CONTROL(base) |= dma__BYTE();
  else *dma_CONTROL(base) &= ~dma__BYTE();
}
inline bool dma1_BYTE(void) { return dma_BYTE(dma1__base()); }
inline void dma1_set_BYTE(bool val) { dma_set_BYTE(dma1__base(), val); }

इस तरह के कोड को मशीन जनरेट किया जाना चाहिए: मैं gsl उपयोग करता हूं (0mq प्रसिद्धि का) एक टेम्पलेट के आधार पर उत्पन्न करने के लिए और कुछ XML इनपुट रजिस्टरों के विवरण को सूचीबद्ध करता है।


बिट फ़ील्ड के लिए कोई मानक नहीं है। मैपिंग और बिट ऑपरेशन इस मामले में संकलक पर निर्भर हैं। बाइनरी मान जैसे 0b0000 भी मानकीकृत नहीं हैं। प्रत्येक बिट के लिए हेक्साडेसिमल मानों को परिभाषित करने का सामान्य तरीका है। उदाहरण के लिए:

#define BYTE (0x01)
#define HW   (0x02)
/*etc*/

जब आप बिट्स सेट करना चाहते हैं, तो आप उपयोग कर सकते हैं:

DMA_base_ptr[DMA_CONTROL_OFFS] |= HW;

या आप के साथ बिट्स साफ़ कर सकते हैं:

DMA_base_ptr[DMA_CONTROL_OFFS] &= ~HW;

पुराने स्कूल सी रास्ता बिट्स का एक गुच्छा परिभाषित करने के लिए है:

#define WORD  0x04
#define GO    0x08
#define I_EN  0x10
#define LEEN  0x80

फिर आपकी इनिशियलाइज़ेशन बन जाती है

DMA_base_ptr[DMA_CONTROL_OFFS] = WORD | GO | LEEN;

आप व्यक्तिगत बिट्स का उपयोग करके सेट कर सकते हैं | :

DMA_base_ptr[DMA_CONTROL_OFFS] |= I_EN;

आप और ~ का उपयोग करके व्यक्तिगत बिट्स को साफ़ कर सकते हैं:

DMA_base_ptr[DMA_CONTROL_OFFS] &= ~GO;

आप व्यक्तिगत बिट्स का उपयोग करके परीक्षण कर सकते हैं:

if(DMA_base_ptr[DMA_CONTROL_OFFS] & WORD) ...

हालांकि, निश्चित रूप से बिटफिल्ड का उपयोग नहीं करते हैं। उनके पास अपने उपयोग हैं, लेकिन नहीं जब एक बाहरी विनिर्देश परिभाषित करता है कि बिट्स कुछ निश्चित स्थानों पर हैं, जैसा कि मैं मानता हूं कि यहां मामला है।

C FAQ सूची में 20.7 और 2.26 प्रश्न भी देखें।





bit