2011-04-28 11 views
14

में एक नौ बिट संख्या का विस्तार मैं एक छोटी, instr है कि इस तरह दिखता है,:साइन सी

1110xxx111111111 

मैं बिट्स 0-9, जो मैं (instr & 0x1FF) के साथ क्या बाहर निकलने के लिए की जरूरत है। इस मात्रा को फिर एक नए शॉर्ट में संग्रहीत किया जाता है। समस्या यह है कि जब ऐसा होता है, तो यह 0x0000000111111111 बन जाता है, 0x1111111111111111 जैसा मैं चाहता हूं। मैं इसे कैसे ठीक करूं? धन्यवाद!

short instr = state->mem[state->pc]; 
unsigned int reg = instr >> 9 & 7; // 0b111 
state->regs[reg] = state->pc + (instr & 0x1FF); 

यह एक सिम्युलेटर है कि विधानसभा में पढ़ता है:

संपादित

कोड यह रहा। state मशीन है, regs[] रजिस्ट्रार हैं और pcmem[] में वर्तमान निर्देश का पता है।

यह ठीक है अगर अंतिम नौ बिट्स सकारात्मक संख्या का प्रतिनिधित्व करते हैं, लेकिन यदि वे -1 का प्रतिनिधित्व कर रहे हैं, तो यह सभी 1 के रूप में संग्रहीत है, जिसे मेरे कोड द्वारा सकारात्मक मूल्य के रूप में समझा जाता है।

+1

सुनिश्चित नहीं हैं कि मैं प्रश्न या प्रक्रिया का उपयोग कर रहे समझते हैं। इन परिणामों को प्राप्त करने के लिए आप जिस कोड का उपयोग कर रहे हैं उसे साझा करने की देखभाल करें? – joce

+0

यह स्पष्ट नहीं है, कौन '0x1111111111111111' बनना चाहिए? – MByD

उत्तर

19

पर मैन्युअल रूप से कर सकती है: (instr & 0x1FF) | ((instr & 0x100) ? 0xFE00 : 0)। यह साइन बिट का परीक्षण करता है (ऊपर की ओर जो आप रख रहे हैं, 0x100) और साइन बिट सेट होने पर इसके ऊपर सभी बिट्स सेट करता है। आप मास्क को 0x1F, 0x10 और 0xFFE0 पर क्रमशः 5 बिट्स, 5 वें बिट और सभी बिट्स 5-16 क्रमशः अनुकूलित करके 5 बिट्स तक बढ़ा सकते हैं।

या आप कोई बहाना के ऊपरी भाग के लिए बिट्स आवंटित करने के लिए मिल सकता है एक छोटी पर हस्ताक्षर किए और उन्हें नीचे शिफ्ट (इस प्रक्रिया में एक साइन-विस्तार हो रही): short x = (instr & 0x1FF) << 7; x >>= 7; बाद वास्तव में विधानसभा में और अधिक सरल होने के खत्म हो सकता है और एक शाखा शामिल नहीं होगा। यदि instr पर हस्ताक्षर किए गए हैं तो यह एक अभिव्यक्ति में किया जा सकता है: (instr & 0x1FF) <<7>> 7। चूंकि यह पहले से ही ऊपरी बिट्स को हटा देता है, यह instr <<7>> 7 को सरल बनाता है। 5 बिट्स (16-5) के लिए 11 के साथ 11 को बदलें।

+0

इसे 5-बिट संख्या के लिए कैसे अनुकूलित किया जा सकता है? मुझे इस कार्यक्रम में दोनों प्रकारों को संभालने की जरूरत है। –

+3

उत्तरार्द्ध पर, क्या आप बस '(instr और 0x1FF << 7) >> 7'? –

+1

मैंने टिप्पणियों को संबोधित करने के लिए उत्तर अपडेट किया है ... –

2

मुझे यकीन नहीं है कि 0x1ff के साथ मास्किंग के बाद आपको 13 1 बिट्स मिल रहे हैं, लेकिन इसे 9-बिट संख्या को 16-बिट शॉर्ट में साइन-अप करना चाहिए। सुंदर नहीं (या विशेष रूप से प्रभावी), लेकिन यह काम करता है:

 
(instr & 0x1ff) | (0xfe00 * ((instr & 0x100) >> 8)) 

संकेत सा बाहर मास्क, 1 की स्थिति में बदलाव 0/1 मिलता है। ऊपरी बिट्स द्वारा इसे गुणा करें, यदि साइन 1 है, तो 9-बिट संख्या 0xfe के साथ होगी, जो सभी ऊपरी बिट्स को 1.

+0

अभी तक इसका परीक्षण नहीं किया है, लेकिन इसे 5-बिट संख्या के लिए कैसे अनुकूलित किया जा सकता है? मुझे इस कार्यक्रम में दोनों प्रकार की आवश्यकता है। और आप परिणामों के बारे में सही हैं; मैं घंटों तक काम कर रहा हूं, इसलिए मैं थक गया हूं। : डी –

+0

साइन बिट को मास्क करें और उस बिट को 1 की स्थिति में बदलें (इसलिए यदि आपके पास ऋणात्मक संख्या है और 0 अन्यथा है तो आपको 1 मिल जाएगा)। फिर विस्तारित बिट्स के लिए एक OR-मुखौटा बनाएं और इसे स्थानांतरित चिह्न से गुणा करें। यदि आपका मूल नंबर नकारात्मक था, तो यह मुखौटा सभी रहेगा, और अन्यथा सभी शून्य होंगे। या यह आपके मास्क किए गए नंबर के साथ ऊपरी बिट्स को 1 के साथ भरने के लिए। –

4
(instr & 0x1FF) * (1 - ((unsigned short)(instr & 0x100) >> 7)) 

यह कैसे काम करता है? यह आपके साइन बिट का चयन करता है और इसे 2 की स्थिति में बदल देता है। इसका उपयोग मूल्य 1 उत्पन्न करने के लिए किया जाता है (यदि आपका साइन बिट अनुपस्थित था) या -1 (यदि आपका साइन बिट मौजूद था)।

यह समाधान शाखा रहित है और यह अनिर्धारित व्यवहार पर निर्भर नहीं है।

+3

एक अज्ञात माइक्रोकंट्रोलर पर मैं शायद गुणा करने के बजाय शाखाकरण के पक्ष में गलती करूंगा। ऐसे CPUs पर शाखा जुर्माना छोटा है और यदि कोई हार्डवेयर गुणक (या यहां तक ​​कि अगर भी है!) बहुत जुर्माना है तो जुर्माना बहुत अधिक है। वास्तव में, कोई * बैरल शिफ्ट का जोखिम दिया * शायद सरल शाखा/परीक्षण सबसे अच्छा है। –

2

बस कुछ और ढूंढने के लिए इसमें थोड़ी देर लग गई, शायद थोड़ा देर हो चुकी है, लेकिन हो सकता है कि यह किसी और के लिए उपयोगी हो। AFAIAC सभी सी प्रोग्रामर प्रोग्रामिंग असेंबलर शुरू करना चाहिए।

वैसे भी विस्तार का संकेत अन्य 2 प्रस्तावों की तुलना में बहुत आसान है। बस सुनिश्चित करें कि आप हस्ताक्षरित चर का उपयोग कर रहे हैं और फिर 2 बदलावों का उपयोग करें।

short instr = state->mem[state->pc]; 
unsigned int reg = (instr >> 9) & 7; // 0b111 
instr &= 0x1ff; // get lower 9 bits 
instr = ((instr << 7) >> 7); // sign extend 
state->regs[reg] = state->pc + instr; 

चर अंकगणित को तो हस्ताक्षर किए है, तो सी संकलक तब्दील >> राइट जो संकेत संरक्षित Shift। यह व्यवहार मंच स्वतंत्र है।

तो, यह सोचते हैं 0x1ff साथ तो हम है कि निर्देप्राप्तगुम शुरू होता है, < < 7 SL (Shift बाएं) होगा मूल्य इतना निर्देप्राप्तगुम अब 0xff80 है, तो >> 7 मूल्य ASR जाएगा ताकि निर्देप्राप्तगुम अब 0xffff है।

+0

क्या इस संदर्भ में "instr & = 0x1ff; // कम 9 बिट्स प्राप्त करें" आवश्यक है? इन बिट्स को किसी भी तरह से धक्का दिया जाता है :) –

8

* कोई आवश्यक शाखाओं में बंटी *

बहुत उपयोगी बिट हैक्स की एक सूची के लिए http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend देखें। विशेष रूप से, पर हस्ताक्षर एक नंबर का विस्तार के रूप में सरल है के रूप में:

/* generate the sign bit mask. 'b' is the extracted number of bits */ 
int m = 1U << (b - 1); 

/* Transform a 'b' bits unsigned number 'x' into a signed number 'r' */ 
int r = (x^m) - m; 

आप उपरोक्त प्रक्रिया उपयोग करने से पहले अगर वे शून्य (x = x & ((1U << b) - 1);) नहीं कर रहे हैं 'एक्स' के ऊपरवाला बिट्स स्पष्ट करने के लिए आवश्यकता हो सकती है।

यदि बिट्स 'बी' की संख्या संकलन समय (जैसे, आपके मामले में 5 बिट्स) पर जानी जाती है तो यहां तक ​​कि एक आसान समाधान भी होता है (यदि प्रोसेसर इसका समर्थन करता है और संकलक है तो यह एक विशिष्ट साइन-विस्तार निर्देश ट्रिगर कर सकता है चालाक पर्याप्त):

struct {signed int x:5;} s; 
r = s.x = x; 
1

यह पिछले जवाब के शोधन के अधिक है, लेकिन कोई पूरी तरह से सामान्य समाधान अब तक प्रस्तुत किया गया है। यह मैक्रो v के साथ sb के साथ साइन-बिट के 0-आधारित बिट नंबर को इंगित करने के लिए एक मान का विस्तार करेगा।

#define SIGNEX(v, sb) ((v) | (((v) & (1 << (sb))) ? ~((1 << (sb))-1) : 0)) 

int32_t x; 

SIGNEX(x, 15); // Sign bit is bit-15 (16th from the right) 
SIGNEX(x, 23); // Sign bit is bit-23 (24th from the right) 

यह प्लेटफॉर्म है कि एक हार्डवेयर गुणा या बैरल शिफ्टर कमी भर में पोर्टेबिलिटी को अधिकतम करने के शाखाओं में उपयोग करता है।

0

एक आसान समाधान यह है, x एक 5-बिट 2 के पूरक संख्या होने के लिए, देखने के लिए:

z = (x^16)-16 
संबंधित मुद्दे