একটি এআরএম কর্টেক্স-এম 4 মাইক্রোকন্ট্রোলারের জন্য গাদা এবং স্ট্যাকের আকার নির্ধারণ করছেন?


11

আমি ছোট এমবেডেড সিস্টেম প্রকল্প চালু এবং বন্ধে কাজ করছি have এর মধ্যে কয়েকটি প্রকল্প একটি এআরএম কর্টেক্স-এম 4 বেস প্রসেসর ব্যবহার করেছে। প্রকল্প ফোল্ডারে একটি স্টার্টআপ.স ফাইল রয়েছে। এই ফাইলের ভিতরে আমি নিম্নলিখিত দুটি কমান্ড লাইন নোট করেছি।

;******************************************************************************
;
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
;
;******************************************************************************
Stack   EQU     0x00000400

;******************************************************************************
;
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;
;******************************************************************************
Heap    EQU     0x00000000

একজন মাইক্রোকন্ট্রোলারের জন্য গাদা এবং স্ট্যাকের আকারটি কীভাবে নির্ধারণ করে ? সঠিক মান পৌঁছানোর জন্য গাইডের জন্য ডেটাশিটে কোনও সুনির্দিষ্ট তথ্য আছে কি? যদি তা হয় তবে ড্যাটাশিটে কী কী সন্ধান করা উচিত?


তথ্যসূত্র:

উত্তর:


12

স্ট্যাক এবং হিপগুলি সফ্টওয়্যার ধারণা, হার্ডওয়্যার ধারণা নয়। হার্ডওয়্যার যা সরবরাহ করে তা হ'ল মেমরি। মেমোরির অঞ্চল নির্ধারণ করে, যার মধ্যে একটিকে "স্ট্যাক" বলা হয় এবং যার মধ্যে একটিটিকে "হিপ" বলা হয়, এটি আপনার প্রোগ্রামের পছন্দ।

হার্ডওয়্যার স্ট্যাকগুলি সাহায্য করে। বেশিরভাগ আর্কিটেকচারের স্ট্যাক পয়েন্টার নামে একটি নিবেদিত নিবন্ধ থাকে। এর উদ্দেশ্যযুক্ত ব্যবহার হ'ল প্রোগ্রামটি যখন কোনও ফাংশন কল করে, ফাংশন প্যারামিটারগুলি এবং ফেরতের ঠিকানাটি স্ট্যাকের দিকে ঠেলে দেওয়া হয় এবং ফাংশনটি শেষ হয়ে যায় এবং তার কলারে ফিরে আসে তখন সেগুলি পপ হয়। স্ট্যাকের দিকে ধাক্কা দেওয়ার অর্থ স্ট্যাক পয়েন্টার দ্বারা প্রদত্ত ঠিকানায় লেখা এবং সেই অনুযায়ী স্ট্যাক পয়েন্টারটি হ্রাস করা (বা বাড়ানো, স্ট্যাকটি কোন দিকে বাড়বে তার উপর নির্ভর করে)। পপিং মানে স্ট্যাক পয়েন্টারটি বাড়ানো (বা হ্রাস করা); প্রত্যাবর্তনের ঠিকানাটি স্ট্যাক পয়েন্টারটির দেওয়া ঠিকানা থেকে পড়া হয়।

কিছু আর্কিটেকচারে (যদিও এআরএম নয়) একটি সাবরুটাইন কল নির্দেশনা রয়েছে যা স্ট্যাক পয়েন্টার দ্বারা প্রদত্ত ঠিকানায় লেখার সাথে লাফ দেয় এবং একটি সাব্রুটিন রিটার্ন নির্দেশ থাকে যা স্ট্যাক পয়েন্টার দ্বারা প্রদত্ত ঠিকানা থেকে পড়া এবং এই ঠিকানায় ঝাঁপিয়ে পড়ে। এআরএম-এ, ঠিকানা সংরক্ষণ এবং পুনরুদ্ধার এলআর রেজিস্টারে করা হয়, কল এবং রিটার্ন নির্দেশাবলী স্ট্যাক পয়েন্টার ব্যবহার করে না। স্ট্যাক পয়েন্টার দ্বারা প্রদত্ত ঠিকানায় একাধিক রেজিস্টার লিখতে বা পড়ার সুবিধার জন্য, ফাংশন আর্গুমেন্টগুলি ধাক্কা দেওয়ার এবং পপ করার জন্য নির্দেশাবলী রয়েছে।

হিপ এবং স্ট্যাকের আকার চয়ন করতে, হার্ডওয়্যার থেকে একমাত্র প্রাসঙ্গিক তথ্য হ'ল আপনার মোট স্মৃতি কত বেশি। তারপরে আপনি মেমরিতে কী সঞ্চয় করতে চান তার উপর নির্ভর করে আপনার পছন্দ করুন (কোড, স্ট্যাটিক ডেটা এবং অন্যান্য প্রোগ্রামের জন্য অনুমতি দেওয়া)।

একটি প্রোগ্রাম সাধারণত এই ধ্রুবকগুলিকে মেমরির কিছু ডেটা আরম্ভ করার জন্য ব্যবহার করে যা বাকী কোড যেমন স্ট্যাকের শীর্ষের ঠিকানা হিসাবে ব্যবহৃত হবে, স্ট্যাকের ওভারফ্লোগুলি যাচাই করার জন্য কোথাও কোনও মান, হিপ বরাদ্দকারীর জন্য সীমাবদ্ধ ইত্যাদি

আপনি যে কোডটি দেখছেন তাতে Stack_Sizeধ্রুবকটি কোড অঞ্চলে মেমরির একটি ব্লক সংরক্ষণ করতে ব্যবহৃত হয় ( SPACEএআরএম অ্যাসেম্বলির নির্দেশের মাধ্যমে )। এই ব্লকের উপরের ঠিকানাটিকে লেবেল দেওয়া হয় __initial_spএবং এটি ভেক্টর টেবিলের মধ্যে সংরক্ষণ করা হয় (প্রসেসর একটি সফ্টওয়্যার রিসেটের পরে এসপি সেট করতে এই এন্ট্রিটি ব্যবহার করে) পাশাপাশি অন্যান্য উত্স ফাইলগুলিতে ব্যবহারের জন্য রফতানি করে। Heap_Sizeধ্রুব একভাবে মেমরি একটি ব্লক রিজার্ভ করতে ব্যবহার করা হয় এবং তার সীমানা (লেবেল করা হয় __heap_baseএবং __heap_limit) অন্য সোর্স ফাইল-এ ব্যবহারের জন্য রপ্তানি করা হয়।

; Amount of memory (in bytes) allocated for Stack
; Tailor this value to your application needs
; <h> Stack Configuration
;   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Stack_Size      EQU     0x00000400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp


; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size       EQU     0x00000200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

…
__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler

…

                 EXPORT  __initial_sp
                 EXPORT  __heap_base
                 EXPORT  __heap_limit

আপনি কী জানেন যে কীভাবে 0x00200 এবং 0x000400 মানগুলি নির্ধারিত হয়
মহেন্দ্র

@ মাহেন্দ্রগুনাওয়ারডেনা আপনার প্রোগ্রামের প্রয়োজনের ভিত্তিতে এগুলি নির্ধারণ করা আপনার কাজ। নিলালের উত্তর কয়েকটি টিপস দেয়।
গিলস 'অশুভ হওয়া বন্ধ করুন'

7

স্ট্যাক এবং হিপগুলির আকারগুলি আপনার অ্যাপ্লিকেশন দ্বারা সংজ্ঞায়িত করা হয়, মাইক্রোকন্ট্রোলারের ডেটাশিটে কোথাও নয়।

স্ট্যাক

স্ট্যাকটি ফাংশনের অভ্যন্তরে স্থানীয় ভেরিয়েবলের মান সংরক্ষণ করতে ব্যবহৃত হয়, স্থানীয় ভেরিয়েবলের জন্য ব্যবহৃত সিপিইউ রেজিস্টারের পূর্বের মানগুলি (যাতে তারা ফাংশন থেকে প্রস্থান করার সময় পুনরুদ্ধার করা যায়), সেই ফাংশনটি রেখে যাওয়ার সময় প্রোগ্রামের ঠিকানা, যোগ স্ট্যাক নিজেই পরিচালনার জন্য কিছু ওভারহেড।

এম্বেড থাকা সিস্টেমটি বিকাশ করার সময়, আপনি যে সর্বাধিক কল ডাইপথটি প্রত্যাশা করেছেন তা অনুমান করে, সেই স্তরক্রমের ফাংশনগুলিতে সমস্ত স্থানীয় ভেরিয়েবলের মাপ যোগ করুন, তারপরে উপরে উল্লিখিত ওভারহেডের জন্য কিছু প্যাডিং যুক্ত করুন, তারপরে আরও কিছু যুক্ত করুন আপনার প্রোগ্রামটি কার্যকর করার সময় যে কোনও বিঘ্ন ঘটতে পারে।

একটি বিকল্প অনুমান পদ্ধতি (যেখানে র‌্যাম সীমাবদ্ধ নয়) আপনার প্রয়োজনের তুলনায় অনেক বেশি স্ট্যাক স্পেস বরাদ্দ করা, একটি সেন্ডিনেল মানটি দিয়ে স্ট্যাকটি পূরণ করুন, তারপরে কার্যকর করার সময় আপনি আসলে কতটা ব্যবহার করেন তা নিরীক্ষণ করুন। আমি সি ভাষার রানটাইমগুলির ডিবাগ সংস্করণগুলি দেখেছি যা এটি আপনার জন্য স্বয়ংক্রিয়ভাবে করবে। তারপরে, আপনি যখন বিকাশ শেষ করেছেন, আপনি চাইলে স্ট্যাকের আকার হ্রাস করতে পারবেন।

গাদা

আপনার প্রয়োজনীয় গাদা আকারের গণনা করা একটি কৌশলযুক্ত হতে পারে। গাদা তাই যদি আপনি ব্যবহার পরিবর্তনশীল বরাদ্দ ভেরিয়েবল ব্যবহার করা হয়, malloc()এবং free()একটি সি ল্যাঙ্গুয়েজ প্রোগ্রাম, অথবা newএবং deleteসি ++ যে যেখানে যারা ভেরিয়েবল বাস।

তবে, বিশেষত সি ++ তে কিছু লুকানো গতিশীল মেমরির বরাদ্দ চলছে। উদাহরণস্বরূপ, যদি আপনার কাছে স্থিতিশীলভাবে বরাদ্দকৃত বস্তু থাকে তবে ভাষাটি প্রোগ্রামের বাইরে এসে তাদের ডেস্ট্রাক্টরদের ডাকা প্রয়োজন। আমি কমপক্ষে একটি রানটাইম সম্পর্কে সচেতন যেখানে ধ্বংসকারীদের ঠিকানাগুলি গতিশীল বরাদ্দযুক্ত লিঙ্ক তালিকায় সংরক্ষণ করা হয়।

সুতরাং আপনার প্রয়োজনীয় স্তূপের আকারটি নির্ধারণ করতে, আপনার কল ট্রি মাধ্যমে প্রতিটি পাথের সমস্ত গতিশীল মেমরির বরাদ্দটি দেখুন, সর্বাধিক গণনা করুন এবং কিছু প্যাডিং যুক্ত করুন। ভাষা রানটাইম ডায়গনিস্টিকগুলি সরবরাহ করতে পারে যা আপনি সম্পূর্ণ হিপ ব্যবহার, খণ্ডন ইত্যাদি পর্যবেক্ষণ করতে ব্যবহার করতে পারেন use


প্রতিক্রিয়াটির জন্য আপনাকে ধন্যবাদ, আমি 0x00400 এবং এর মতো নির্দিষ্ট নম্বর কীভাবে নির্ধারণ করতে পারি তা পছন্দ করতে চাই
মহেন্দ্র

5

অন্যান্য উত্তরগুলির পাশাপাশি, আমি যুক্ত করতে চাই যে স্ট্যাক এবং হিপ স্পেসের মধ্যে র‌্যাম তৈরি করার সময়, আপনাকে স্ট্যাটিক অ ধ্রুবক ডেটার জন্যও স্থান বিবেচনা করতে হবে (যেমন ফাইল গ্লোবাল, ফাংশন স্ট্যাটিক্স এবং প্রোগ্রাম-ওয়াইড সি দৃষ্টিকোণ থেকে গ্লোবালগুলি এবং সি ++ এর জন্য সম্ভবত অন্যরা)।

কীভাবে স্ট্যাক / গাদা বরাদ্দ কাজ করে

এটি লক্ষণীয় যে স্টার্টআপ সমাবেশ ফাইলটি অঞ্চলটিকে সংজ্ঞায়নের এক উপায়; টুলচেন (আপনার বিল্ড এনভায়রনমেন্ট এবং রান-টাইম এনভায়রনমেন্ট উভয়ই) বেশিরভাগ প্রতীকগুলিকে যত্ন করে যা স্ট্যাকস্পেসের সূচনা (ভেক্টর টেবিলের মধ্যে প্রাথমিক স্ট্যাক পয়েন্টার সংরক্ষণের জন্য ব্যবহৃত হয়) এবং হিপ স্পেসের শুরু এবং শেষ (গতিশীল দ্বারা ব্যবহৃত) মেমরি বরাদ্দকারী, সাধারণত আপনার libc দ্বারা সরবরাহ করা হয়)

ওপি-র উদাহরণে, কেবল 2 টি প্রতীক সংজ্ঞায়িত করা হয়, 1kiB তে স্ট্যাকের একটি আকার এবং 0 বি তে একটি আকারের। এই মানগুলি স্ট্যাক এবং হিপ স্পেসগুলি তৈরি করতে অন্য কোথাও ব্যবহৃত হয়

@ গিলস উদাহরণে, আকারগুলি স্ট্যাক_মিমে প্রতীক দ্বারা চিহ্নিত এবং আকার স্থায়ীভাবে স্থায়ীভাবে সেট করার জন্য অ্যাসেম্বলি ফাইলটিতে সংজ্ঞায়িত এবং ব্যবহৃত হয় এবং শেষে __initial_sp একটি লেবেল সেট করে। অনুরূপভাবে স্তূপের জন্য, যেখানে স্থানটি হিপ_মিম (আকারে 0.5KB) প্রতীক, তবে শুরু এবং শেষের লেবেল সহ (__heap_base এবং __heap_limit)।

এগুলি লিঙ্কারের মাধ্যমে প্রক্রিয়াজাত হয়, যা স্ট্যাক স্পেস এবং হিপ স্পেসের মধ্যে কোনও কিছুই বরাদ্দ দেয় না কারণ সেই স্মৃতিটি দখল করা আছে (স্ট্যাক_মেম এবং হিপ_মিম চিহ্ন দ্বারা) তবে এটি সেই স্মৃতিগুলি এবং সমস্ত গ্লোবাল যেখানেই এটি প্রয়োজন সেখানে স্থাপন করতে পারে। লেবেলগুলি প্রদত্ত ঠিকানাগুলিতে দৈর্ঘ্য ছাড়াই প্রতীক হিসাবে শেষ হয়। __Initial_sp লিংক সময়ে সরাসরি ভেক্টর টেবিলের জন্য এবং আপনার রানটাইম কোড দ্বারা __heap_base এবং __heap_limit ব্যবহার করা হয়। চিহ্নগুলির প্রকৃত ঠিকানাগুলি লিঙ্কার যেখানে স্থাপন করেছিল তার উপর ভিত্তি করে নির্ধারিত হয়।

আমি উপরে জোর দিয়েছি, এই চিহ্নগুলি আসলে একটি স্টার্টআপ.স ফাইল থেকে আসে না। এগুলি আপনার লিঙ্কার কনফিগারেশন (কেইলে স্ক্যাটার লোড ফাইল, জিএনইউতে লিংস্ক্রিপ্ট) থেকে আসতে পারে এবং সেগুলির মধ্যে আপনার বসানো উপর সূক্ষ্ম দানাদার নিয়ন্ত্রণ থাকতে পারে। উদাহরণস্বরূপ, আপনি স্ট্যাকটি রামের শুরুতে বা শেষ হতে বাধ্য করতে পারেন, বা আপনার গ্লোবালগুলি গাদা থেকে দূরে রাখতে পারেন, বা যা আপনি চান। এমনকি আপনি উল্লেখ করতে পারেন যে গ্লোবাল স্থাপনের পরে যে পরিমাণ র‌্যাম র‌্যাম বাকি আছে কেবল হিপ বা স্ট্যাক কেবল দখল করে। উল্লেখ্য যে আপনার অন্যান্য স্মৃতি হ্রাস পাবে এমন স্থিতিশীল ভেরিয়েবল যুক্ত করার ক্ষেত্রে আপনাকে সতর্ক থাকতে হবে।

তবে, প্রতিটি সরঞ্জামচইন আলাদা এবং কনফিগারেশন ফাইলটি কীভাবে লিখবেন এবং আপনার গতিশীল মেমরির বরাদ্দকারী কী চিহ্ন ব্যবহার করবে তা আপনার নির্দিষ্ট পরিবেশের ডকুমেন্টেশন থেকে আসতে হবে।

স্ট্যাক সাইজিং

স্ট্যাকের আকার কীভাবে নির্ধারণ করা যায় সে বিষয়ে অনেক সরঞ্জামচেন আপনার প্রোগ্রামের ফাংশন কল ট্রিগুলি বিশ্লেষণ করে আপনাকে সর্বাধিক স্ট্যাকের গভীরতা দিতে পারে, যদি আপনি পুনরাবৃত্তি বা ফাংশন পয়েন্টার ব্যবহার না করেন। যদি আপনি সেগুলি ব্যবহার করেন, কোনও স্ট্যাকের আকার অনুমান করে এবং এটি মূল মানগুলি (সম্ভবত প্রধানের আগে প্রবেশের ফাংশন দিয়ে) দিয়ে পূর্বে পূরণ করে এবং তারপরে আপনার প্রোগ্রামটি পরীক্ষা করার পরে সর্বাধিক গভীরতা কোথায় ছিল (যা সেখানে কার্ডিনাল মানগুলি শেষ). আপনি যদি নিজের প্রোগ্রামটির সীমাবদ্ধতার সাথে পুরোপুরি অনুশীলন করে থাকেন তবে আপনি স্ট্যাকটি সঙ্কুচিত করতে পারবেন কিনা বা আপনার প্রোগ্রাম ক্র্যাশ হয়ে গেছে বা কোনও প্রাথমিক মান বাকি আছে কিনা তা আপনি পুরোপুরি সঠিকভাবে জানতে পারবেন যে আপনাকে স্ট্যাকটি বাড়িয়ে আবার চেষ্টা করতে হবে।

হিপ সাইজিং

হ্যাপের আকার নির্ধারণ করা আরও বেশি অ্যাপ্লিকেশন নির্ভর। আপনি যদি প্রারম্ভকালীন সময়ে কেবল গতিশীল বরাদ্দ করেন, আপনি কেবল আপনার স্টার্টআপ কোডে প্রয়োজনীয় স্থানটি যুক্ত করতে পারেন (মেমরি পরিচালনার জন্য কিছু ওভারহেড)। আপনার মেমরি পরিচালকের উত্সটিতে অ্যাক্সেস থাকলে আপনি ওভারহেড কী তা সঠিকভাবে জানতে পারবেন এবং সম্ভবত ব্যবহারের তথ্য দেওয়ার জন্য মেমরিটিতে হাঁটার জন্য কোড লিখতেও পারেন। অ্যাপ্লিকেশনগুলির জন্য যা ডায়নামিক রানটাইম মেমরির প্রয়োজন (উদাহরণস্বরূপ ইনবাউন্ড ইথারনেট ফ্রেমের জন্য বাফার বরাদ্দ করা) আমার পক্ষে সবচেয়ে ভাল পরামর্শ দেওয়া হ'ল সতর্কতার সাথে আপনার স্ট্যাকসাইজ হোন করা এবং স্ট্যাক এবং স্ট্যাটিক্সের পরে যে সমস্ত জিনিস রেখে দেওয়া হয়েছে তা হিপটি দেওয়া।

চূড়ান্ত নোট (আরটিওএস)

ওপির প্রশ্নটি খালি-ধাতুর জন্য ট্যাগ করা ছিল, তবে আমি আরটিওসগুলির জন্য একটি নোট যুক্ত করতে চাই। প্রায়শই (সর্বদা?) প্রতিটি কাজ / প্রক্রিয়া / থ্রেড (সরলতার জন্য আমি কেবল এখানে টাস্কটি লিখব) যখন টাস্কটি তৈরি করা হবে তখন একটি স্ট্যাকের আকার নির্ধারণ করা হবে, টাস্ক স্ট্যাকের পাশাপাশি একটি ছোট ওএস থাকবে স্ট্যাক (বিঘ্ন এবং এই জাতীয় জন্য ব্যবহৃত)

টাস্ক অ্যাকাউন্টিং স্ট্রাকচার এবং স্ট্যাকগুলি কোথাও থেকে বরাদ্দ করতে হবে এবং এটি প্রায়শই আপনার আবেদনের সামগ্রিক স্তূপ স্থান থেকে হবে। এই উদাহরণগুলিতে, আপনার প্রাথমিক স্ট্যাকের আকারটি প্রায়শই কোনও ব্যাপার নয়, কারণ ওএস কেবলমাত্র আরম্ভের সময় এটি ব্যবহার করবে। আমি দেখেছি, উদাহরণস্বরূপ, সংযোগের সময় সমস্ত অবশিষ্ট স্থান নির্দিষ্ট করে হিপকে বরাদ্দ করতে হবে এবং গাদা শেষে প্রারম্ভিক স্ট্যাক পয়েন্টার রেখে গাদা হয়ে উঠতে হবে, জেনেও যে ওএস গাদা শুরু থেকে শুরু করবে এবং প্রাথমিক_এসপি স্ট্যাকটি পরিত্যাগ করার ঠিক আগে ওএস স্ট্যাক বরাদ্দ করবে। তারপরে সমস্ত জায়গাগুলি টাস্ক স্ট্যাকগুলি বরাদ্দকরণ এবং অন্যান্য গতিশীল বরাদ্দ মেমরির জন্য ব্যবহৃত হয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.