آدرس‌دهی کلمه‌ای

در معماری رایانه، آدرس دهی کلمه‌ای  به این معنی است که آدرس‌های حافظه در یک رایانه به‌طور منحصر به فرد کلمات حافظه را مشخص می‌کند. معمولاً در مقابل این روش آدرس دهی بایتی استفاده می‌شود، جایی که آدرس‌ها به‌طور منحصر به فرد بایت‌ها را شناسایی می‌کنند. تقریباً تمام معماری‌های رایانه‌ای مدرن از آدرس‌دهی به صورت بایت استفاده می‌کنند و آدرس‌دهی کلمه عمدتاً تنها از منظر تاریخی بررسی می‌شود. رایانه ای که از آدرس دهی کلمه استفاده می‌کند، گاهی ماشین کلمه نامیده می‌شود.

مبانی و مفاهیم پایه 
رایانه‌ای را در نظر بگیرید که می‌تواند ۵۲۴،288 (2 19) بیت حافظه را فراهم کند. اگر آن حافظه با استفاده از بایت‌های ۸ بیتی در یک فضای آدرس مسطح آدرس‌دهی بایتی، با استفاده از بایت‌های ۸ بیتی مرتب شده باشد، آنگاه 65536 (2 16) آدرس معتبر، از ۰ تا ۶۵٬۵۳۵ وجود دارد که هر یک نشان‌دهنده ۸ بیت حافظه مستقل است. اگر در عوض در یک فضای آدرس مسطح قابل آدرس دهی کلمه با استفاده از کلمات ۳۲ بیتی مرتب شده باشد، 16384 (2 14) آدرس معتبر از ۰ تا ۱۶۳۸۳ وجود دارد که هر کدام نشان دهنده ۳۲ بیت مستقل است.

به‌طور کلی، حداقل واحد آدرس پذیر در رم (MAU: Minimum Addressable Unit) یک ویژگی خاص از حافظه است. انتزاع‌های مختلف در یک رایانه ممکن است از MAUهای متفاوتی استفاده کنند، حتی زمانی که آنها یک حافظه اصلی را نشان می‌دهند. به عنوان مثال، ممکن است یک رایانه برای مجموعه دستورالعمل‌ها instruction set خود از آدرس‌های ۳۲ بیتی استفاده کند، اما سیستم انسجام حافظه پنهان(cache coherence) CPU ممکن است با حافظه تنها با ریز دانگی(granularity) 64 بایت خطوط کش(cache lines)کار کند، که اجازه می‌دهد هر یک از خطوط کش با تنها یک آدرس ۲۶ بیتی شناسایی شود و سربار حافظه نهان CPU کاهش یابد.

ترجمه آدرس که توسط حافظه مجازی(virtual memory) انجام شده‌است اغلب بر ساختار و عرض فضای آدرس تأثیر می‌گذارد، اما MAU را تغییر نمی‌دهد.

trade-off بین حداقل واحدهای آدرس پذیر مختلف 
تصمیم برای انتخاب اندازه حداقل واحد آدرس پذیر حافظه می‌تواند می‌تواند سخت باشد. استفاده از یک MAU بزرگتر اجازه می‌دهد تا همان مقدار حافظه را با یک آدرس کوچکتر آدرس دهی شود، که می‌تواند به میزان قابل توجهی نیازهای یک برنامه به حافظه را کاهش دهد. با این حال، استفاده از یک MAU کوچکتر، باعث آسانتر و بهینه تر شدن کار با داده‌های کوچک می‌شود.

فرض کنید برنامه ای می‌خواهد یکی از ۱۲ نشانه سنتی طالع بینی غربی را ذخیره کند. یک علامت واحد را می‌توان در ۴ بیت ذخیره کرد. اگر یک علامت در حداقل واحد آدرس پذیر خود ذخیره شود، اگر از آدرس دهی بایت استفاده شود ۴ بیت استفاده نخواهد شد و ۵۰٪ بازده خواهیم داشت، در حالی که در آدرس دهی کلمه ۳۲ بیتی ۲۸ بیت استفاده نخواهد شد و ۱۲٫۵٪ بازده خواهیم داشت. اگر یک علامت در مینیمم واحد آدرس پذیر MAU با داده‌های دیگر «بسته‌بندی» شود، آنگاه ممکن است هزینه خواندن و نوشتن در حافظه به نسبت افزایش یابد. برای مثال، برای نوشتن یک علامت جدید در MAU که دادهٔ دیگری نیز در آن بسته‌بندی شده، رایانه ابتدا باید مقدار فعلی داخل MAU را خوانده و تنها بیت‌های مناسب را بازنویسی کند و در نهایت مقدار جدید را مجدداً ذخیره کند. در صورتی که برنامه نیاز داشته باشد تا به نخ (thread)های مختلف اجازه دهد تا داده‌های دیگر داخل MAU را به‌طور همزمان تغییر دهد این عملیات بسیار هزینه برخواهد بود.

مثال رایج تر، رشته‌ای از متن است. فرمت‌های رایج برای ذخیره رشته‌ها مانند UTF-8 و ASCII رشته‌ها را به صورت دنباله ای از کد پوینت‌های ۸ بیتی ذخیره می‌کنند. با آدرس دهی به صورت بایت، هر کد می‌تواند در MAU با آدرس دهی مستقل خود بدون هیچ سرباری ذخیره شود. با آدرس دهی کلمه ای ۳۲ بیتی و قرار دادن هر کد پوینت داخل یک MAU جداگانه باعث افزایش استفاده از حافظه به میزان ۳۰۰٪ می‌شود که برای برنامه‌هایی که با رشته‌های بزرگ کار می‌کنند مناسب و قابل اجرا نیست. دسته‌بندی کدهای مجاور درون یک کلمه حافظه باعث جلوگیری از این هزینه می‌شود، هر چند الگوریتم‌های زیادی برای کار با رشته‌ها ترجیح می‌دهند تا بتوانند آدرس‌های مستقل برای کدها در نظر بگیرند. برای اینکه این کار را بتوان با کدهای دسته‌بندی شده انجام داد الگوریتم باید از یک آدرس "wide" یا گسترده یا عریض استفاده کند که همچنین آفست یا محل کاراکتر در کلمه حافظه را مشخص می‌کند. اگر قرار باشد این آدرس گسترده در جایی در حافظه برنامه ذخیره شود ممکن است به حافظه بیشتری نسبت به آدرس‌های معمولی نیاز داشته باشد.

برای ارزیابی تأثیر این روش‌ها در یک برنامه کامل، یک مرورگر را در نظر بگیرید که صفحه ای بزرگ و پیچیده را نمایش می‌دهد. برخی از قسمت‌های حافظه مرورگر برای ذخیره داده‌های ساده مانند عکس‌ها یا متون استفاده می‌شود، مرورگر غالباً می‌خواهد که این داده‌ها به شکل بهینه‌ترین حالت ممکن ذخیره شوند، و در نتیجه تقریباً به همان مقدار داده حافظه اشغال شود بدون اینکه به اندازه MAU توجهی شود. قسمت دیگر حافظه برای ذخیره اشیا مختلف صفحه در مرورگر می‌باشد، و این اشیا شامل تعداد زیادی ارجاع هستند که این ارجاع‌ها می‌توانند به اشیا دیگر صفحه، متون و عکس‌ها و … باشند. مقدار حافظه مورد نیاز برای ذخیره این اشیا بستگی زیادی به عرض آدرس رایانه دارد.

فرض کنید اگر تمام آدرس‌های برنامه ۳۲ بیتی بود، این صفحه وب حدود ۱۰ گیگابایت حافظه اشغال می‌کرد.
 اگر مرورگر روی یک رایانه با آدرس‌های ۳۲ بیتی و حافظه آدرس پذیر به صورت بایت در حال اجرا باشد، فضای آدرس ۴ گیگا بایت از حافظه را پوشش خواهد داد که کافی نمی‌باشد. مرورگر یا قادر نخواهد بود که صفحه را نمایش دهد یا باید برخی داده‌ها را به حافظه کندتر منتقل کند، که در نتیجه این کارایی و عملکرد آن کاهش می‌یابد.
 اگر مرورگر در یک رایانه با حافظه آدرس پذیر به صورت بایت و آدرس‌های ۶۴ بیتی در حال اجرا باشد، به‌طور قابل ملاحظه ای به حافظهٔ بیشتری برای ذخیره آدرس‌ها نیاز خواهد داشت. به‌طور دقیق تر، سربار بستگی به این دارد که چه مقدار از ۱۰ گیگابایت داده به صورت داده‌های ساده و جه مقدار از آن به شکل اشیا (object) و رفرنس‌های متراکم می‌باشد، اما رقم ۴۰ درصد غیرقابل قبول نیست وقتی در نهایت به ۱۴ گیگابایت حافظه نیاز است. که البته این به خوبی در توانایی‌های فضای آدرس ۶۴ بیتی است. اگر چه معمولاً مرورگر وضعیت بدتری را نمایش می‌دهد و با فرض برابری منابع با گزینه‌های جایگزین، از حافظه نهان (cache) رایانه استفاده بدتری می‌کند.
 اگر مرورگر روی یک رایانه با آدرس‌های ۳۲ بیتی و حافظه آدرس پذیر کلمه ای ۳۲ بیتی باشد، به احتمال زیاد به دلیل دسته‌بندی‌های غیر بهینه و نیاز به تعدادی آدرس عریض "wide" به مقداری حافظه اضافی نیاز دارد. این کار به دلیل اینکه مرورگر برای اکثر کارها از دسته‌بندی و آدرس‌های غیر عریض استفاده می‌کند و مرورگر به راحتی در محدوده آدرس پذیر حداکثر ۱۶ گیگابایت قرار می‌گیرد تأثیر نسبتاً کمی دارد. اگر چه ممکن است به دلیل استفاده گسترده از داده‌های بسته‌بندی شده برای عکس‌ها و متن سربار قابل توجی در زمان اجرا ایجاد شود. مهم‌تر از آن ۱۶ گیگابایت محدودیت نسبتاً کمی است و اگر صفحه مرورگر به‌طور قابل توجهی رشد کند، کامپیوتر فضای آدرس خود را تمام می‌کند و مشکلات مشابهی که در رایانه‌های آدرس بایت داشتیم نمایان می‌شود.
 اگر مرورگر روی یک رایانه با آدرس‌های ۶۴ بیتی و حافظه آدرس پذیر کلمه ای ۳۲ بیتی اجرا شود، از هر دو سربار زمان اجرا که در بالا گفته شد رنج خواهد برد: به‌طور قابل توجهی به حافظه بیشتری نیاز خواهد داشت تا آدرس‌ها ۶۴ بیتی را ذخیره کند و در همین حال به دلیل کار با بسته‌بندی‌های بزرگ داده‌های عکس و متن باعث ایجاد سربار در زمان اجرا می‌شود. آدرس دهی کلمه ای به این معنی است که برنامه می‌تواند از نظر تئوری به جای ۱۶ اگزابایت، ۶۴ اگزابایت حافظه را آدرس دهی کند، هرچند به این دلیل که یک برنامه هیچ‌گاه نیاز به این مقدار حافظه ندارد (و در عمل هیچ رایانه‌ای توانایی فراهم کردن آن را ندارد)، این ویژگی هیچ سودی ندارد.

بنابر این، آدرس دهی کلمه ای به رایانه اجازه می‌دهد که به‌طور قابل ملاحظه ای میزان بیشتری از حافظه را آدرس دهی کند بدون اینکه عرض آدرس‌ها و در نتیجه آن میزان استفاده متناظر از حافظه افزایش یابد. هر چند این ویژگی تنها در محدوده نسبتاً کوچکی از مجموعه اندازه کاری ارزشمند است و می‌تواند بسته به نرم‌افزار باعث سربارهای قابل توجهی شود. برنامه‌هایی که به‌طور نسبی با کارهای اندکی با داده‌هایی که به صورت بایت هستند مانند عکس، متن، فایل‌ها و ترافیک شبکه انجام می‌دهند می‌توانند بیشترین فایده را داشته باشند.

دسترسی‌های زیر کلمه و آدرس‌های گسترده 
برنامه ای که روی رایانه در حال اجرا می‌باشد و از آدرس دهی کلمه ای استفاده می‌کند، همچنان می‌تواند با شبیه‌سازی دسترسی به واحدهای کوجک تر، با واحدهای کوچک‌تر حافظه کار کند. برای بارگذاری نیاز داریم کلمه را برداشته و سپس بیت‌های مورد نظر را استخراج کنیم. برای ذخیره نیز نیاز داریم کلمه را بارگذاری کنیم، مقادیر جدید را در آن قرار دهیم و پس از بازنویسی بیت‌های مورد نظر آن را مجدداً در کلمه موجود در حافظه ذخیره کنیم.

فرض کنید چهار کد پوینت متوالی رشته با فرمت UTF-8 را می‌خواهیم در یک کلمه ۳۲ بیتی دسته‌بندی کنیم. اولین کد ممکن است بیت‌های ۰ تا ۷، دومین کد ۸ تا ۱۵، سومین ۱۶–۲۳ و کد چهارم بین‌های ۲۴–۳۱ را اشغال کند. (اگر حافظه قابل آدرس دهی بایت بود، این یک ترتیب بایت انددی است.)

به منظور روشن شدن واضح کد لازم برای دسترسی به زیر کلمه بدون اینکه مثال را خیلی مشابه معماری آدرس دهی کلمه ای خاصی در نظر بگیریم، مثال‌های زیر از اسمبلی MIPS استفاده می‌کنند. در واقعیت MIPS یک معماری آدرس دهی بایتی با پشتیبانی مستقیم از بارگذاری و ذخیره‌سازی مقادیر ۸ و ۱۶ بیتی است، اما مثال وانمود می‌کند که تنها از بارگذاری و ذخیره ۳۲-بیتی که در یک کلمه ۳۲ بیتی است باید جدا از یک آدرس ذخیره شود. معماری MIPS انتخاب شده‌است به دلیل اینکه یک زبان اسمبلی ساده و بدون امکانات تخصصی است که باعث راحت تر شدن این عملیات می‌شود.

فرض کنید یک برنامه می‌خواهد سومین کد را در ثبات r1 از کلمه ای داخل آدرسی در ثبات r2 بخواند. با در نظر گرفتن عدم وجود پشتیبانی از مجموعه دستورالعمل‌ها (instruction set)، برنامه باید تمام کلمه را بارگذاری کند، ۱۶ بار شیفت به راست انجام دهد تا دو کد ابتدا را حذف کند و سپس کد چهارم را پنهان کند.
  ldw $r1, 0($r2) # Load the full word
  srl $r1, $r1, 16 # Shift right by 16
  andi $r1, $r1, 0xFF # Mask off other code points
اگر آفست به‌طور ایستا (استاتیک) مشخص نباشد، اما در عوض یک بیت-آفست در ثبات r3 ذخیره شده باشد، رویکرد کمی پیچیده‌تر نیاز است.
  ldw $r1, 0($r2) # Load the full word
  srlv $r1, $r1, $r3 # Shift right by the bit offset
  andi $r1, $r1, 0xFF # Mask off other code points
فرض کنید به‌جای آن برنامه می‌خواهد کد پوینت داخل رجیستر r1 به سومین کد پوینت داخل کلمه در رجیستر r2 قرار دهد. با در نظر گرفتن عدم پشتیبانی از مجموعه دستورالعمل‌ها (instruction set)، برنامه باید تمام کلمه را بارگذاری کند، مقدار قدیمی آن کد پوینت را پنهان کند، مقدار جدید را در محل مورد نظر تغییر دهد و پس از ادغام کردن مقادیر، تمام کلمه را دوباره ذخیره کند.
  sll $r1, $r1, 16 # Shift the new value left by 16
  lhi $r5, 0x00FF # Construct a constant mask to select the third byte
  nor $r5, $r5, $zero # Flip the mask so that it clears the third byte
  ldw $r4, 0($r2) # Load the full word
  and $r4, $r5, $r4 # Clear the third byte from the word
  or $r4, $r4, $r1 # Merge the new value into the word
  stw $r4, 0($r2) # Store the result as the full word
مجدداً، اگر افست به جای آن در ثبات r3 ذخیره شود، رویکرد پیچیده تری مورد نیاز است:
  sllv $r1, $r1, $r3 # Shift the new value left by the bit offset
  llo $r5, 0x00FF # Construct a constant mask to select a byte
  sllv $r5, $r5, $r3 # Shift the mask left by the bit offset
  nor $r5, $r5, $zero # Flip the mask so that it clears the selected byte
  ldw $r4, 0($r2) # Load the full word
  and $r4, $r5, $r4 # Clear the selected byte from the word
  or $r4, $r4, $r1 # Merge the new value into the word
  stw $r4, 0($r2) # Store the result as the full word
این دنباله کد فرض می‌کند که یک نخ (thread) دیگر نمی‌تواند بایت‌های دیگر داخل کلمه را همزمان تغییر دهد. اگر تغییرات همزمان ممکن بود، آنگاه ممکن بود یکی از تغییرات صورت نگیرد. برای حل این مشکل، چند دستورالعمل آخر باید به یک حلقه مقایسه-تبدیل تجزیه ناپذیر (atomic) تبدیل شوند تا یک تغییر همزمان به راحتی باعث شود تا عملیات با مقادیر جدید تکرار شود. در این مورد هیج مانعی برای حافظه لازم نیست.

به یک جفت آدرس کلمه و یک آفست درون کلمه آدرس عریض یا گستره (wide - همچنین fat address یا fat pointer) گفته می‌شود. (این را نباید با دیگر کاربردهای آدرس‌های عریض برای ذخیره‌سازی انواع مختلف داده‌های تکمیلی مانند کران‌های یک آرایه اشتباه گرفت) آفست ذخیره شده ممکن است یک بیت-آفست یا بایت-آفست باشد. دنباله کدهای بالا از این مورد که آفست به صورت بیت ذخیره می‌شود سود می‌برند، زیرا از آن به عنوان تعداد شیفت استفاده می‌کنند. یک معماری با پشتیبانی مستقیم برای انتخاب بایت، ممکن است ترجیح دهد تا فقط یک بایت آفست ذخیره کند.

در این دنباله‌های کد، آفست اضافی باید در کنار آدرس پایه ذخیره شود که در نتیجه آن عملاً نیازهای کلی ذخیره‌سازی آدرس را دو برابر می‌کند. این همیشه در رابطه با ماشین‌های کلمه ای صادق نیست، عمدتاً برای این که خود آدرس‌ها در کنار دیگر داده‌ها بسته‌بندی نمی‌شوند تا دسترسی به آن‌ها کارآمدتر باشد. برای مثال، Cray X1 از کلمات ۶۴ بیتی استفاده می‌کند، اما آدرس‌ها تنها ۳۲ بیت هستند. هنگامی که یک آدرس در حافظه ذخیره می‌شود، در کلمه مربوط به خودش ذخیره می‌شود و در نتیجه آفست بایت می‌تواند در ۳۲ بیت با ارزش تر کلمه قرار گیرد. ناکارآمدی استفاده از آدرس‌های عریض در این سیستم تنها منطق اضافی برای دستکاری این آفست و استخراج و درج بایت‌ها داخل کلمات است و تأثیری در استفاده از حافظه ندارد.

مفاهیم مرتبط 
حداقل واحد قابل آدرس دهی در رایانه لزوماً با حداقل اندازه دسترسی به رم در مجموعهٔ دستورالعمل‌های رایانه یکی نیست. برای مثال یک رایانه ممکن است از آدرس دهی بایت بدون اینکه هیچ دستوری برای خواندن و نوشتن روی یک بایت ارائه شود استفاده کند. از برنامه‌ها انتظار می‌رود که آن عملیات را به صورت نرم‌افزاری با تغییر دادن بیت‌ها انجام دهند، مانند دنباله کدهایی که در بالا آورده شد. این کار در رایانه‌ها با معماری ۶۴ بیتی که به عنوان جانشین ابر رایانه‌ها یا مینی رایانه‌های ۳۲ هستند، مانند DEC Alpha و Cray X1 نسبتاً رایج است.

استاندارد C بیان می‌کند که از یک اشاره گر انتظار می‌رود که نمایش معمول یک آدرس را در خود داشته باشد. C همچنین به یک اشاره گر اجازه می‌دهد که برای هر شی یا اشیاء به جز یک فیلد بیت ایجاد شود. این شامل هر هر عنصر مجزا از آرایه ای از بایت‌ها می‌شود. کامپایلرهای سی در رایانه‌هایی که از آدرس دهی کلمه ای استفاده می‌کنند معمولاً از نمایش‌های متفاوتی برای اشاره گرها بسته به اندازه نوع آنها استفاده می‌کنند. یک اشاره گر به یک نوع داده که به اندازه کافی برای قرارگیری در یک کلمه بزرگ است به شکل یک آدرس ساده می‌باشد، در حالی که یک اشاره گر مانند char* یا void* یک آدرس عریض خواهد بود: یک جفت آدرس از یک کلمه و آفست یک بایت داخل آن کلمه؛ بنابراین، تبدیل میان انواع متخلف اشاره گرها عملیات ساده ای نخواهد بود و ممکن است در صورت اشتباه انجام شدن آن، داده‌ها از بین بروند.

به دلیل اینکه اندازه یک struct در سی همواره موقع تصمیم‌گیری برای نمایش یک اشاره گر به آن struct مشخص نیست، نمی‌توان به‌طور قابل اعتمادی قوانین بالا را اعمال کرد. ممکن است کامپایلرها نیاز داشته باشند که محل شروع یک struct را مشخص و تراز کنند تا بتوان از نمایش‌های کارا تری برای اشاره گر استفاده کنند.

مثال‌ها 
 ERA 1103 از آدرس دهی کلمه ای با کلمات ۳۶-بیتی استفاده می‌کند. تنها آدرس‌های ۰ تا ۱۰۲۳ به حافظه رم ارجاع می‌کنند، دیگر آدرس یا به جایی اشاره نمی‌کنند یا برای ارجاع به حافظه drum استفاده می‌شود.
 PDP-10 از آدرس دهی کلمه ای با کلمات ۳۶-بیتی و آدرس‌های ۱۸ بیتی استفاده می‌کرد.
 اغلب ابر کامپیوترهای Cray بین سال‌های ۱۹۸۰ و ۱۹۹۰ از آدرس دهی کلمه ای با کلمات ۶۴ بیتی استفاده می‌کردند. ابر کامپیوترهای Cray-1 و Cray X-MP از آدرس‌های ۲۴ بیتی استفاده می‌کردند در حالی که اغلب دیگر ابر کامپیوترها آدرس‌های ۳۲ بیتی استفاده می‌کردند.
 Cray X1 از آدرس دهی بایت با آدرس‌های ۶۴ بیتی استفاده می‌کند. این کامپیوتر به‌طور مستقیم از دسترسی به حافظه کمتر از ۶۴ بیت پشتیبانی نمی‌کرد، و دسترسی‌های این گونه باید به‌طور نرم‌افزاری شبیه‌سازی شود. کامپایلر C برای X1 اولین کامپایلر Cray بود که از شبیه‌سازی برای دسترسی ۱۶ بیتی به حافظه استفاده می‌کرد.
 DEC Alpha از آدرس دهی بایت با آدرس‌های ۶۴ بیتی استفاده می‌کند. پردازنده‌های اولیه Alpha از دسترسی مستقیم ۱۶ بیتی و ۸ بیتی برای حافظه پشتیبانی نمی‌کردند و برای مثال نرم‌افزارها نیاز داشتند تا یک بایت را با بارگذاری تمام ۶۴ بیت کلمه و سپس استخراج آن یک بایت بارگذاری کنند. به دلیل اینکه Alpha از آدرس دهی بایت استفاده می‌کند، این آفست همچنان در کم ارزش‌ترین بیت‌های آدرس مشخص می‌شود (به حای اینکه به‌طور جداگانه به شکل آدرس عریض یا wide باشد)، و Alpha به راحتی از دستورهای العمل‌های بدون تراز بارگذاری و ذخیره مانند (ldq_u و stq_u) با نادیده گرفتن آن بیت‌ها و بارگذاری و ذخیره‌سازی کلمه تراز شده، فراهم می‌کند. با شروع از Alpha 21164a افزونه‌های بایت-کلمه بعدی به معماری (BWX: byte-word extensions) بارگذاری و ذخیره‌سازی‌های ۸ و ۱۶ بیتی را اضافه کرد. اضافه کردن مجدد این افزونه بدون ایجاد ناسازگاری‌های جدی ممکن بود زیرا Alpha همواره از آدرس دهی بایت استفاده می‌کرد.

جستارهای وابسته 
 آدرس دهی بایت

منابع 

حافظه رایانه