'\" e .\" .\" SPDX-License-Identifier: MIT .\" .Dd August 1, 2026 .Dt RGBASM 5 .Os .SH "نام (NAME)" rgbasm \- مستندات زبان اسمبلی Game Boy .Sh "توضیحات (DESCRIPTION)" این توضیحات کامل زبان اسمبلی مورد استفاده توسط .Xr rgbasm 1 است. برای توضیحات کامل دستورالعمل‌های زبان ماشین پشتیبانی‌شده توسط پردازنده Game Boy، به .Xr gbz80 7 مراجعه کنید. .Pp توصیه می‌شود پیش از خواندن این سند، تا حدی با سخت‌افزار Game Boy آشنایی داشته باشید. RGBDS به‌طور ویژه برای Game Boy هدف‌گذاری شده است، بنابراین بسیاری از ویژگی‌های آن مستقیماً با مفاهیم سخت‌افزاری آن گره خورده‌اند. این سند به عنوان مرجع سخت‌افزار Game Boy در نظر گرفته نشده است. .Pp به‌طور کلی، .Dq پیونددهنده به .Xr rgblink 1 اشاره دارد، اما هر برنامه‌ای که فایل‌های شیء RGBDS (توضیح داده شده در .Xr rgbds 5 ) را پردازش کند، می‌تواند به جای آن استفاده شود. .Sh "ساختار دستوری (SYNTAX)" ساختار دستوری، درست مانند هر اسمبلر دیگری، مبتنی بر خط است. هر خط می‌تواند شامل بخش‌هایی به یکی از این دو ترتیب باشد: .Bl -bullet -offset indent .It .Oo Ar label : Oc Oo Ar directive Oc Oo ;\ Ns Ar comment Oc .It .Oo Ar label : Oc Oo Ar instruction Oo :: Ar instruction ... Oc Oc Oo ;\ Ns Ar comment Oc .El .Pp شبه‌دستورها (Directives) فرمان‌هایی به خود اسمبلر هستند، مانند .Ic PRINTLN ، .Ic SECTION ، یا .Ic OPT . .Pp برچسب‌ها یک نام را به مکانی مشخص درون یک بخش پیوند می‌دهند (به .Sx Labels در ادامه مراجعه کنید). برچسب‌ها قبل از اکثر شبه‌دستورها مجاز هستند، اما قبل از .Ic IF ، .Ic ELIF ، .Ic ELSE ، .Ic ENDC ، .Ic REPT ، .Ic FOR ، .Ic ENDR ، .Ic MACRO ، یا .Ic ENDM مجاز نیستند. .Pp دستورالعمل‌ها به آپ‌کدهای Game Boy ترجمه (اسمبل) می‌شوند. چندین دستورالعمل در یک خط، و همچنین شبه‌دستورهای داده (به .Sx Defining constant data in ROM در ادامه مراجعه کنید)، می‌توانند با دو دونقطه .Ql :: از یکدیگر جدا شوند. .Pp دستورالعمل‌های موجود در .Xr gbz80 7 مستند شده‌اند. .Pp توجه داشته باشید در جایی که یک دستورالعمل به یک ثبات ۸ بیتی .Ar r8 نیاز دارد، .Nm می‌تواند .Ic HIGH Ns Pq Ar r16 را به عنوان ثبات ۸ بیتی بالایی از .Ar r16 داده‌شده تفسیر کند؛ برای مثال، .Ic HIGH Ns Pq Ic HL برای .Ic H ؛ و .Ic LOW Ns Pq Ar r16 را به عنوان ثبات پایینی تفسیر کند؛ برای مثال، .Ic LOW Ns Pq Ic HL برای .Ic L (به‌جز برای .Ic LOW Ns Pq Ic AF ، زیرا .Ic F یک ثبات معتبر نیست). .Pp همچنین توجه داشته باشید در جایی که یک دستورالعمل به یک کد وضعیت .Ar cc نیاز دارد، .Nm می‌تواند .Ic ! Ns Ar cc را به عنوان کد وضعیت معکوس تفسیر کند؛ برای مثال، .Ic !nz برای .Ic z . .Pp تمام کلیدواژه‌های رزروشده (شبه‌دستورها، دستورالعمل‌ها، ثبات‌ها، توابع داخلی و غیره) به حروف بزرگ و کوچک حساس نیستند (case-insensitive)؛ تمام شناسه‌ها (برچسب‌ها، متغیرها و غیره) به حروف بزرگ و کوچک حساس هستند (case-sensitive). .Pp توضیحات (Comments) برای ارائه اطلاعاتی درباره کد به انسان‌ها، مانند توضیحات تکمیلی، استفاده می‌شوند. اسمبلر .Em همیشه توضیحات و محتوای آن‌ها را نادیده می‌گیرد. .Pp دو نوع توضیح وجود دارد: درون‌خطی و بلوکی. توضیحات درون‌خطی هر چیزی هستند که پس از یک نقطه‌ویرگول .Ql \&; که درون یک رشته نباشد، تا انتهای خط قرار می‌گیرند. توضیحات بلوکی، که با .Ql /* آغاز شده و با .Ql */ پایان می‌یابند، می‌توانند در چندین خط پخش شوند یا در میان یک عبارت قرار گیرند. .Pp مثالی که این ویژگی‌های ساختار دستوری را نشان می‌دهد: .Bd -literal -offset indent SECTION "My Code", ROM0\ \ ;\ a directive MyFunction:\ \ \ \ \ \ \ \ \ \ \ \ \ \ ;\ a label push hl\ \ \ \ \ \ \ \ \ \ \ \ \ \ ;\ an instruction /* ...and multiple instructions, with mixed case */ ld a, [hli] :: LD H, [HL] :: Ld l, a pop /*wait for it*/ hl ret .Ed .Pp گاهی اوقات خطوط ممکن است بسیار طولانی شوند و شکستن آن‌ها ضروری باشد. برای این کار، یک بک‌اسلش در انتهای خط قرار دهید: .Bd -literal -offset indent DB 1, 2, 3,\ \e 4, 5, 6,\ \e\ ;\ Put it before any comments 7, 8, 9 DB "Hello,\ \e\ \ ;\ Space before the \e is included world!"\ \ \ \ \ \ \ \ \ \ \ ;\ Any leading space is included .Ed .Ss "درج نماد (Symbol interpolation)" نمادهایی با مقادیر رشته‌ای یا عددی می‌توانند با نوشتن آن‌ها درون .Ql {braces} .Dq درج شوند (interpolated). این کار محتوای نماد را طوری جای‌گذاری می‌کند که گویی بخشی از فایل منبع بوده‌اند. اگر یک نماد رشته‌ای باشد، نویسه‌های آن به همان صورت درج می‌شوند. اگر یک نماد عددی باشد، مقدار آن به نمادگذاری هگزادسیمال با یک علامت دلار .Sq $ در ابتدا تبدیل می‌شود. .Pp درج نمادها می‌تواند تودرتو نیز باشد. .Bd -literal -offset indent DEF topic EQUS "life, the universe, and \e"everything\e"" DEF meaning EQUS "answer" ;\ Defines answer = 42 DEF {meaning} = 42 ;\ Prints "The answer to life, the universe, and "everything" is $2A" PRINTLN "The {meaning} to {topic} is {{meaning}}" PURGE topic, meaning, {meaning} .Ed .Pp نمادها را می‌توان حتی در زمینه‌هایی که بسط خودکار ثابت‌های رشته‌ای را غیرفعال می‌کنند درج کرد: یعنی .Ql name در تمام موارد .Ql DEF({name}) ، .Ql DEF {name} EQU/=/EQUS/etc ... ، .Ql REDEF {name} EQU/=/EQUS/etc ... ، .Ql FOR {name}, ... ، .Ql PURGE {name} ، و .Ql MACRO {name} بسط داده خواهد شد، هرچند در .Ql DEF(name) ، .Ql PURGE {name} و غیره بسط داده نخواهد شد. .Pp امکان تغییر نحوه چاپ نمادها با مشخص کردن قالب چاپ به این صورت وجود دارد: .Ql {fmt:symbol} . مشخص‌کننده .Ql fmt از بخش‌هایی تشکیل شده که باید به ترتیب زیر باشند: .Ql . تمام این بخش‌ها اختیاری هستند، به‌جز .Ql که الزامی است. این بخش‌ها عبارتند از: .Bl -column "" .It Sy Part Ta Sy Meaning .It Ql Ta می‌تواند .Ql + یا .Ql \ باشد. در صورت تعیین، این نویسه را در جلوی اعداد غیرمنفی چاپ می‌کند. .It Ql Ta می‌تواند .Ql # باشد .Pq تنها برای انواع غیرده‌دهی مجاز است . در صورت تعیین، مقدار را در قالبی «دقیق» چاپ می‌کند: با یک پیشوند مبنا .Pq So $ Sc ، So & Sc ، یا So % Sc برای انواع صحیح غیرده‌دهی .Pq So x Sc / So X Sc ، So o Sc ، یا So b Sc ؛ با یک پسوند دقت .Ql q برای اعداد ممیز ثابت؛ یا با نویسه‌های گریز .Ql \e (اما بدون گیومه‌های محصورکننده) برای رشته‌ها. .It Ql Ta می‌تواند .Ql - باشد. در صورت تعیین، به جای راست، از چپ تراز می‌کند. .It Ql Ta می‌تواند .Ql 0 باشد. در صورت تعیین، اعداد راست‌تراز را به جای فاصله با صفر پر می‌کند. .It Ql Ta می‌تواند یک یا چند نویسه .Ql 0 \[en] .Ql 9 باشد. در صورت تعیین، مقدار را تا این پهنا پر می‌کند که به‌طور پیش‌فرض با فاصله از راست تراز می‌شود. .It Ql Ta می‌تواند .Ql \&. باشد که با صفر یا چند نویسه .Ql 0 \[en] .Ql 9 دنبال می‌شود. در صورت تعیین، این تعداد ارقام کسری از یک عدد ممیز ثابت را چاپ می‌کند. به‌طور پیش‌فرض ۵ رقم است و حداکثر ۲۵۵ رقم می‌باشد. (یک .Ql \&. که با صفر رقم .Ql 0 \[en] .Ql 9 دنبال شود، صفر رقم کسری و بدون ممیز اعشاری چاپ می‌کند.) .It Ql Ta می‌تواند .Ql q باشد که با یک یا چند نویسه .Ql 0 \[en] .Ql 9 دنبال می‌شود. در صورت تعیین، یک عدد ممیز ثابت را با این دقت چاپ می‌کند. به‌طور پیش‌فرض روی گزینه جاری .Fl Q تنظیم است. .It Ql Ta نوع مقدار را مشخص می‌کند. .El .Pp انواع معتبر عبارتند از: .Bl -column -offset indent "Type" "Lowercase hexadecimal" "Example" .It Sy Type Ta Sy Format Ta Sy Example .It Ql d Ta ده‌دهی علامت‌دار Ta -42 .It Ql u Ta ده‌دهی بدون علامت Ta 4294967254 .It Ql x Ta هگزادسیمال با حروف کوچک Ta 2a .It Ql X Ta هگزادسیمال با حروف بزرگ Ta 2A .It Ql b Ta باینری (دودویی) Ta 101010 .It Ql o Ta اکتال (هشت‌هشتی) Ta 52 .It Ql f Ta ممیز ثابت Ta 1234.56789 .It Ql s Ta رشته Ta string contents .El .Pp مثال‌ها: .Bd -literal -offset indent SECTION "Test", ROM0[2] X: ;\ This works with labels **whose address is known** DEF Y = 3 ;\ This also works with variables DEF SUM EQU X + Y ;\ And likewise with numeric constants ; Prints "%0010 + $3 == 5" PRINTLN "{#05b:X} + {#x:Y} == {d:SUM}" rsset 32 DEF PERCENT rb 1 ;\ Same with offset constants DEF VALUE = 20 DEF RESULT = MUL(20.0, 0.32) ; Prints "32% of 20 = 6.40" PRINTLN "{d:PERCENT}% of {d:VALUE} = {f:RESULT}" DEF WHO EQUS STRLWR("WORLD") ; Prints "Hello world!" PRINTLN "Hello {s:WHO}!" .Ed .Pp اگرچه برای این مثال‌ها، .Ic STRFMT مناسب‌تر خواهد بود؛ به .Sx String expressions در ادامه مراجعه کنید. .Sh "عبارات (EXPRESSIONS)" دو نوع عبارت وجود دارد: عددی و رشته‌ای. .Pp عبارات عددی همیشه با استفاده از محاسبات ۳۲ بیتی علامت‌دار ارزیابی می‌شوند. در زمینه‌های منطق بولی، صفر تنها عدد «نادرست» (false) در نظر گرفته می‌شود و تمام اعداد غیرصفر (از جمله منفی) «درست» (true) هستند. .Pp یک عبارت «ثابت» نامیده می‌شود اگر .Nm مقدار آن را بداند. این عموماً همیشه صادق است، مگر اینکه برچسبی در میان باشد، همان‌طور که در بخش .Sx SYMBOLS توضیح داده شده است. با این حال، برخی از عملگرها حتی با عملوندهای غیرثابت نیز می‌توانند ثابت باشند، همان‌طور که در .Sx Operators در ادامه توضیح داده شده است. .Pp شبه‌دستورها معمولاً نیازمند عبارات ثابت هستند: برای مثال، .Ic REPT نیاز دارد که تعداد تکرارها در زمان ترجمه کد (assembly time) مشخص باشد. .Ss "لیترال‌های عددی (Numeric literals)" .Nm از انواع مختلف لیترال‌های عددی پشتیبانی می‌کند. .Bl -column -offset indent "Precise fixed-point" "Prefixes" "Accepted characters" .It Sy Format type Ta Sy Prefixes Ta Sy Accepted characters .It ده‌دهی Ta ندارد Ta 0123456789 .It هگزادسیمال Ta Li $ , 0x , 0X Ta 0123456789ABCDEF .It اکتال Ta Li & , 0o , 0O Ta 01234567 .It باینری Ta Li % , 0b , 0B Ta 01 .It ممیز ثابت Ta ندارد Ta 01234.56789 .It ممیز ثابت دقیق Ta ندارد Ta 12.34q8 .It ثابت نویسه‌ای Ta ندارد Ta 'A' .It گرافیک Game Boy Ta Li \` Ta 0123 .El .Pp خط زیرین (_) نیز در اعداد پذیرفته می‌شود، به‌جز در ابتدای عدد. این می‌تواند برای گروه‌بندی ارقام مفید باشد، مانند .Ql 123_456 یا .Ql %1100_1001 . .Pp شکل «ثابت نویسه‌ای» مقداری را به دست می‌دهد که نویسه در جدول نگاشت نویسه (charmap) جاری به آن نگاشت شده است. برای مثال، به‌طور پیش‌فرض .Pq به Xr ascii 7 مراجعه کنید .Sq 'A' مقدار ۶۵ را به دست می‌دهد. یک ثابت نویسه‌ای باید یک مقدار واحد را نشان دهد، بنابراین نمی‌تواند شامل چندین نویسه یا نویسه‌هایی باشد که به چندین مقدار نگاشت می‌شوند. برای اطلاعات درباره نگاشت‌های نویسه به .Sx Character maps و برای اطلاعات درباره نویسه‌های گریز مجاز در ثابت‌های نویسه‌ای به .Sx String expressions مراجعه کنید. .Pp مورد آخر، گرافیک Game Boy، حداکثر تا هشت رقم بین ۰ و ۳ را انتظار دارد که متناظر با مقادیر سایه دو بیتی پیکسل‌ها هستند. مقدار عددی حاصل، دو بایت داده تایل است که آن سطر از پیکسل‌ها را تولید می‌کند. برای مثال، .Sq \`01012323 معادل .Sq $0F55 است. .Pp به جای یک لیترال عددی، می‌توانید از نام یک نماد عددی نیز استفاده کنید که به‌طور ضمنی با مقدار آن جایگزین می‌شود. .Ss "عملگرها (Operators)" می‌توانید از این عملگرها در عبارات عددی استفاده کنید (فهرست‌شده از بیشترین به کمترین اولویت): .Bl -column -offset indent "!= == <= >= < >" .It Sy Operator Ta Sy Meaning .It Li \&( \&) Ta گروه‌بندی .It Li FUNC() Ta فراخوانی تابع داخلی .It Li ** Ta به توان رساندن .It Li + - ~ \&! Ta مثبت یگانی، منفی یگانی (قرینه‌سازی)، متمم (نقیض بیتی)، و نقیض بولی .It Li * / % Ta ضرب، تقسیم (گرد کردن به پایین)، و مدول (باقیمانده) .It Li << >> >>> Ta شیفت‌های بیتی (به چپ، به راست با بسط علامت، به راست با بسط صفر) .It Li & \&| ^ Ta عملگرهای بیتی AND/OR/XOR .It Li + - Ta جمع و تفریق .It Li == != < > <= >= Ta مقایسه‌ها .It Li && Ta عملگر بولی AND .It Li || Ta عملگر بولی OR .El .Pp .Sq ** عددی را به توان غیرمنفی می‌رساند. این تنها عملگر .Em راست‌تداعی است، به این معنی که .Ql p ** q ** r برابر است با .Ql p ** (q ** r) ، نه .Ql (p ** q) ** r . تمام عملگرهای دوگانی دیگر چپ‌تداعی هستند. .Pp .Sq ~ یک مقدار را با معکوس کردن تمام ۳۲ بیت آن متمم می‌کند. .Pp .Sq % برای دریافت باقیمانده تقسیم متناظر استفاده می‌شود، به‌طوری که .Ql x / y * y + x % y == x همیشه درست باشد. حاصل دارای همان علامت مقسوم‌علیه است. این باعث می‌شود .Ql x % y برابر با .Ql (x + y) % y یا .Ql (x - y) % y باشد. .Pp شیفت دادن با جابجایی تمام بیت‌ها در عملوند سمت چپ به چپ .Pq Sq << یا به راست .Pq Sq >> به میزان مقدار عملوند سمت راست انجام می‌شود. هنگام شیفت به چپ، تمام بیت‌های تازه درج‌شده صفر می‌شوند؛ هنگام شیفت به راست، به جای آن کپی‌هایی از باارزش‌ترین بیت اصلی هستند. این امر .Sq a << b و .Sq a >> b را به ترتیب معادل ضرب و تقسیم بر ۲ به توان b می‌کند. .Pp عملگرهای مقایسه اگر مقایسه نادرست باشد ۰، و در غیر این صورت ۱ را برمی‌گردانند. .Pp برخلاف بسیاری از زبان‌های دیگر، و به دلایل فنی، .Nm همچنان هر دو عملوند .Sq && و .Sq || را ارزیابی می‌کند. .Pp عملگرهای .Sq && و .Sq & با یک ثابت صفر به عنوان هر یک از عملوندها، مقدار ثابت ۰ خواهند بود، و .Sq || با یک ثابت غیرصفر به عنوان هر یک از عملوندها، مقدار ثابت ۱ خواهد بود، حتی اگر عملوند دیگر غیرثابت باشد. .Pp .Sq \&! اگر عملوند ۰ باشد ۱ را برمی‌گرداند، و در غیر این صورت ۰ را برمی‌گرداند. حتی یک عملوند غیرثابت با هر بیت غیرصفر مقدار ۰ را برمی‌گرداند. .Ss "توابع اعداد صحیح (Integer functions)" علاوه بر عملگرها، توابعی نیز وجود دارند که کاربردهای تخصصی‌تری دارند: .Bl -column "BITWIDTH(n)" .It Sy Name Ta Sy Operation .It Fn HIGH n Ta معادل با Ql Po Ns Ar n No & $FF00 Pc >> 8 . .It Fn LOW n Ta معادل با Ql Ar n No & $FF . .EQ delim $$ .EN .It Fn BITWIDTH n Ta تعداد بیت‌های لازم برای نمایش .Ar n را برمی‌گرداند. برخی فرمول‌های مفید: .Ic BITWIDTH Ns ( Ar n Ns )\ \-\ 1 برابر با $\[lf] log sub 2 ( n ) \[rf]$ است؛ .Ic BITWIDTH Ns Pq Ar n Ns \ \-\ 1 برابر با $\[lc] log sub 2 ( n ) \[rc]$ است؛ و .No 32\ \-\ Ns Ic BITWIDTH Ns Pq Ar n برابر با $roman clz ( n )$، یعنی تعداد بیت‌های صفر آغازین در نمایش باینری .Ar n است. .It Fn TZCOUNT n Ta مقدار $roman ctz ( n )$، یعنی تعداد بیت‌های صفر پایانی در نمایش باینری .Ar n را برمی‌گرداند. .El .EQ delim off .EN .Ss "عبارات ممیز ثابت (Fixed-point expressions)" اعداد ممیز ثابت از نظر فنی همان اعداد صحیح هستند، اما از نظر مفهومی دارای ممیز اعشاری در مکانی ثابت هستند (به همین دلیل این نام را دارند). این امر به آن‌ها دقت بیشتری می‌دهد، به بهای دامنه کوچک‌تر، در حالی که دستکاری آن‌ها بسیار کم‌هزینه‌تر از اعداد ممیز شناور باقی می‌ماند (که .Nm از آن‌ها پشتیبانی نمی‌کند). .Pp دقت پیش‌فرض تمام اعداد ممیز ثابت ۱۶ بیت است، به این معنی که ۱۶ بیت پایینی برای بخش کسری استفاده می‌شوند؛ بنابراین آن‌ها در واحدهای یک شصت‌وپنج‌هزاروپانصدوسی‌وششم (65536ths) از ۱.۰ شمارش می‌شوند. این دقت را می‌توان با گزینه خط فرمان .Fl Q و/یا با .Ic OPT Q تغییر داد .Pq به Sx Changing options while assembling مراجعه کنید . یک لیترال ممیز ثابت مجزا می‌تواند دقت خود را مشخص کند و پیش‌فرض جاری را لغو نماید، با افزودن یک .Dq q که پس از آن تعداد بیت‌های کسری می‌آید: برای مثال، .Ql 789.25q8 برابر با $000315_40 .EQ delim $$ .EN ($= 789.25 * 2 sup 8$) است. .Pp از آنجا که مقادیر ممیز ثابت همچنان همان اعداد صحیح هستند، می‌توانید از آن‌ها در عبارات عادی اعداد صحیح استفاده کنید. به‌راحتی می‌توانید یک عدد ممیز ثابت را با شیفت دادن آن به راست به تعداد بیت‌های کسری، یا با تقسیم آن بر ۱.۰، به یک عدد صحیح برش دهید (truncate). نتیجه می‌شود که می‌توانید یک عدد صحیح را با شیفت دادن آن به چپ به همان میزان، یا با ضرب کردن آن در ۱.۰، به یک عدد ممیز ثابت تبدیل کنید. برای مثال، .Ql 123.0 / 1.0 == 123 ، و .Ql 123 * 1.0 == 123.0 . .Pp توجه داشته باشید که تعداد بیت‌های کسری جاری را می‌توان به صورت .Ic TZCOUNT Ns Pq 1.0 محاسبه کرد. .Pp توابع زیر برای کار با اعداد ممیز ثابت طراحی شده‌اند (که باید ثابتِ مشخص باشند): .Bl -column -offset indent "ATAN2(y, x)" .It Sy Name Ta Sy Operation .It Fn DIV x y Ta تقسیم ممیز ثابت .It Fn MUL x y Ta ضرب ممیز ثابت .It Fn FMOD x y Ta مدول ممیز ثابت .It Fn POW x y Ta $x sup y$ .It Fn LOG x y Ta لگاریتم $x$ در مبنای $y$ .It Fn ROUND x Ta گرد کردن $x$ به نزدیک‌ترین عدد صحیح (نیمه به دور از صفر) .It Fn CEIL x Ta گرد کردن $x$ به بالا به نزدیک‌ترین عدد صحیح .It Fn FLOOR x Ta گرد کردن $x$ به پایین به نزدیک‌ترین عدد صحیح .It Fn SIN x Ta سینوس $x$ .It Fn COS x Ta کسینوس $x$ .It Fn TAN x Ta تانژانت $x$ .It Fn ASIN x Ta وارون سینوس $x$ .It Fn ACOS x Ta وارون کسینوس $x$ .It Fn ATAN x Ta وارون تانژانت $x$ .It Fn ATAN2 y x Ta زاویه بین $( x , y )$ و $( 1 , 0 )$ .El .EQ delim off .EN .Pp هیچ تابعی برای جمع و تفریق ممیز ثابت وجود ندارد، زیرا عملگرهای .Sq + و .Sq - می‌توانند جفت عملوندهای ممیز ثابت را با هم جمع و تفریق کنند. .Bd -ragged -offset indent توجه داشته باشید که برخی عملگرها یا توابع هنگام ترکیب اعداد صحیح و مقادیر ممیز ثابت معنادار هستند. برای مثال، .Ql 2.0 * 3 معادل با .Ql MUL(2.0, 3.0) است، و .Ql 6.0 / 2 معادل با .Ql DIV(6.0, 2.0) است. هنگام انجام این نوع کارها مراقب باشید و در مورد معنای عملیات‌ها فکر کنید. .Ed .Pp همه این توابع ممیز ثابت می‌توانند یک آرگومان نهایی اختیاری بگیرند که دقتی است که باید برای همان یک عملیات استفاده شود. برای مثال، .Ql MUL(6.0q8, 7.0q8, 8) صرف‌نظر از اینکه چه مقداری به عنوان گزینه جاری .Cm Q تنظیم شده باشد، به .Ql 42.0q8 ارزیابی می‌شود. .Nm .Em سازگاری دقت‌ها را بررسی نمی‌کند ، بنابراین ورودی بی‌معنی مانند .Ql MUL(4.2q8, 6.9q12, 16) نتیجه‌ای بی‌معنی (اما از نظر فنی صحیح) تولید خواهد کرد: .Dq خروجی بی‌ارزش حاصل ورودی بی‌ارزش است (garbage in, garbage out) . .Pp تابع .Ic FMOD برای به دست آوردن باقیمانده تقسیم ممیز ثابت متناظر استفاده می‌شود. نتیجه دارای همان علامت .Em مقسوم است؛ این برعکس نحوه کار عملگر مدول اعداد صحیح .Sq % است! .Pp توابع مثلثاتی .Pq Ic SIN ، Ic COS ، Ic TAN ، و غیره بر حسب دایره‌ای تقسیم‌شده به ۱.۰ .Dq دور (turn) .EQ delim $$ .EN (برابر با $2 pi$ رادیان، یا ۳۶۰ درجه) تعریف شده‌اند. .EQ delim off .EN .Pp این توابع برای تولید خودکار جداول مختلف مفید هستند. برای مثال: .Bd -literal -offset indent ; Generate a table of 128 sine values ; from sin(0.0) included to sin(0.5) excluded, ; with amplitude scaled from [-1.0, 1.0] to [0.0, 128.0], ; then divided by 1.0 to round down to integer values. FOR angle, 0.0, 0.5, 0.5 / 128 db MUL(SIN(angle) + 1.0, 128.0 / 2) / 1.0 ENDR .Ed .Ss "عبارات رشته‌ای (String expressions)" ابتدایی‌ترین عبارت رشته‌ای، یک لیترال رشته‌ای است: هر تعداد نویسه که درون گیومه دوتایی قرار گرفته باشند .Pq Ql \&"for instance" . نویسه بک‌اسلش .Ql \e خاص است از این جهت که باعث می‌شود نویسه بعد از آن .Dq گریز داده شود (escaped) ، به این معنی که به گونه‌ای متفاوت از حالت معمول با آن رفتار می‌شود. تعدادی توالی گریز وجود دارد که می‌توانید درون یک رشته استفاده کنید: .Bl -column -offset indent "Sequence" .It Sy Sequence Ta Sy Meaning .It Ql \e\e Ta بک‌اسلش Pq خود نویسه گریز را گریز می‌دهد .It Ql \e" Ta گیومه دوتایی Pq به رشته پایان نمی‌دهد .It Ql \e' Ta گیومه تکی Pq به لیترال نویسه‌ای پایان نمی‌دهد .It Ql \e{ Ta آکولاد باز Pq درج نماد را آغاز نمی‌کند .It Ql \e} Ta آکولاد بسته Pq به درج نماد پایان نمی‌دهد .It Ql \en Ta خط جدید Pq ASCII $0A .It Ql \er Ta بازگشت به ابتدای سطر (Carriage return) Pq ASCII $0D .It Ql \et Ta تب Pq ASCII $09 .It Ql \e0 Ta نال Pq ASCII $00 .El .Pp لیترال‌های رشته‌ای چندخطی در گیومه‌های سه‌تایی قرار می‌گیرند .Pq Ql \&"\&"\&"for instance""" . توالی‌های گریز در رشته‌های چندخطی به همان صورت کار می‌کنند؛ با این حال، نویسه‌های خط جدید تحت‌اللفظی به همان شکل گنجانده می‌شوند، بدون نیاز به گریز دادن آن‌ها با .Ql \er یا .Ql \en . .Pp لیترال‌های رشته‌ای خام با یک علامت هش .Sq # پیشوندگذاری می‌شوند. درون آن‌ها، بک‌اسلش‌ها و آکولادها مانند نویسه‌های معمولی تلقی می‌شوند، بنابراین به عنوان آرگومان‌های ماکرو، نمادهای درج‌شده یا توالی‌های گریز بسط داده نخواهند شد. برای مثال، رشته خام .Ql #"\et\e1{s}\e" معادل با رشته معمولی .Ql \&"\e\et\e\e1\e{s}\e\e" است. (توجه داشته باشید که این امر مانع از گنجاندن نویسه گیومه دوتایی در رشته‌های خام می‌شود.) رشته‌های خام نیز ممکن است درون گیومه‌های سه‌تایی قرار گیرند تا چندخطی باشند، بنابراین می‌توانند شامل نویسه‌های خط جدید یا گیومه تحت‌اللفظی باشند (هرچند همچنان سه گیومه متوالی مجاز نیست). .Pp می‌توانید از عملگر .Sq ++ برای الحاق دو رشته استفاده کنید. .Ql \&"str" ++ \&"ing" معادل با .Ql \&"string" ، یا معادل با .Ql STRCAT("str", \&"ing") است. .Pp می‌توانید از عملگرهای .Sq === و .Sq !== برای مقایسه دو رشته استفاده کنید. .Ql \&"str" === \&"ing" معادل با .Ql STRCMP("str", \&"ing") == 0 ، و .Ql \&"str" !== \&"ing" معادل با .Ql STRCMP("str", \&"ing") != 0 است. .Pp توابع زیر روی عبارات رشته‌ای عمل می‌کنند و خودشان رشته برمی‌گردانند: .Bl -column "STRSLICE(str, start, stop)" .It Sy Name Ta Sy Operation .It Fn STRCAT strs... Ta رشته‌های Ar strs را الحاق می‌کند . .It Fn STRUPR str Ta رشته Ar str No را با تمام حروف اسکی .Pq Ql a-z به صورت حروف بزرگ برمی‌گرداند. .It Fn STRLWR str Ta رشته Ar str No را با تمام حروف اسکی .Pq Ql A-Z به صورت حروف کوچک برمی‌گرداند. .It Fn STRSLICE str start stop Ta یک زیررشته از Ar str No را که از Ar start No آغاز شده و به Ar stop No ختم می‌شود (غیرشامل) برمی‌گرداند. اگر Ar stop No مشخص نشده باشد، زیررشته تا انتهای Ar str ادامه می‌یابد. .It Fn STRRPL str old new Ta رشته Ar str No را با جایگزینی هر رخداد زیررشته Ar old No با Ar new برمی‌گرداند. .It Fn STRFMT fmt args... Ta رشته Ar fmt No را بازمی‌گرداند در حالی که هر الگوی .Ql %spec با درج قالب .Ar spec .Pq با استفاده از همان ساختار دستوری Sx Symbol interpolation با آرگومان متناظر آن در .Ar args جایگزین شده است .Pq So %% Sc با نویسه So % Sc جایگزین می‌شود . .It Fn STRCHAR str idx Ta زیررشته‌ای از Ar str No را برای ورودی جدول نگاشت نویسه در اندیس Ar idx No با نگاشت نویسه جاری برمی‌گرداند . Pq Ar idx No ورودی‌های نگاشت نویسه را می‌شمارد، نه نویسه‌ها را. .El .Pp توابع زیر عملوندهای مختلفی می‌گیرند و رشته برمی‌گردانند: .Bl -column "READFILE(name, max)" .It Fn REVCHAR vals... Ta رشته‌ای را که با نگاشت نویسه جاری به Ar vals نگاشت شده برمی‌گرداند. اگر ورودی نگاشت نویسه یکتایی برای Ar vals وجود نداشته باشد، خطا رخ می‌دهد. .It Fn READFILE name max Ta محتوای فایل Ar name No را به صورت رشته برمی‌گرداند. حداکثر تا Ar max No بایت را می‌خواند، یا اگر Ar max No مشخص نشده باشد، کل محتوا را می‌خواند. اگر فایل در دایرکتوری جاری یافت نشود، فهرست مسیرهای include ارائه‌شده به گزینه Fl I دستور Xr rgbasm 1 در خط فرمان جستجو خواهد شد. .El .Pp توابع زیر روی عبارات رشته‌ای عمل می‌کنند، اما اعداد صحیح برمی‌گردانند: .Bl -column "STRRFIND(str, sub)" .It Sy Name Ta Sy Operation .It Fn STRLEN str Ta تعداد نویسه‌ها در Ar str را برمی‌گرداند. .It Fn STRCMP str1 str2 Ta رشته‌های Ar str1 No و Ar str2 No را بر اساس ترتیب اسکی نویسه‌هایشان مقایسه می‌کند. اگر Ar str1 No کمتر از Ar str2 باشد -1، اگر Ar str1 No بزرگتر از Ar str2 باشد 1، و اگر با هم مطابقت داشته باشند 0 برمی‌گرداند. .It Fn STRFIND str sub Ta اولین اندیس رخداد Ar sub No در Ar str را برمی‌گرداند، یا اگر موجود نباشد -1 برمی‌گرداند. .It Fn STRRFIND str sub Ta آخرین اندیس رخداد Ar sub No در Ar str را برمی‌گرداند، یا اگر موجود نباشد -1 برمی‌گرداند. .It Fn BYTELEN str Ta تعداد بایت‌ها در Ar str را برمی‌گرداند. Pq نویسه‌های غیراسکی می‌توانند چندین بایت باشند. .It Fn STRBYTE str idx Ta مقدار بایت را در اندیس Ar idx No در Ar str برمی‌گرداند. .It Fn INCHARMAP str Ta اگر Ar str No ورودی‌ای در نگاشت نویسه جاری داشته باشد 1، و در غیر این صورت 0 برمی‌گرداند. .It Fn CHARLEN str Ta تعداد ورودی‌های نگاشت نویسه در Ar str No را با نگاشت نویسه جاری برمی‌گرداند. .It Fn CHARCMP str1 str2 Ta رشته‌های Ar str1 No و Ar str2 No را بر اساس مقادیر ورودی‌های نگاشت نویسه آن‌ها با نگاشت نویسه جاری مقایسه می‌کند. اگر Ar str1 No کمتر از Ar str2 باشد -1، اگر Ar str1 No بزرگتر از Ar str2 باشد 1، و اگر با هم مطابقت داشته باشند 0 برمی‌گرداند. .It Fn CHARSIZE char Ta تعداد مقادیر موجود در ورودی نگاشت نویسه برای Ar char No را با نگاشت نویسه جاری برمی‌گرداند. .It Fn CHARVAL char idx Ta مقدار موجود در اندیس Ar idx No از ورودی نگاشت نویسه برای Ar char را برمی‌گرداند. اگر Ar idx No مشخص نشده باشد، Ar char No باید دارای یک مقدار واحد باشد که همان برگردانده می‌شود. .El .Pp توجه داشته باشید که اندیس‌ها از ابتدا با ۰، یا از انتها با ۱- شمارش می‌شوند. نویسه‌های یک رشته توسط .Ql STRLEN ؛ ورودی‌های نگاشت نویسه یک رشته توسط .Ql CHARLEN ؛ و مقادیر یک ورودی نگاشت نویسه توسط .Ql CHARSIZE شمارش می‌شوند. .Ss "نگاشت‌های نویسه (Character maps)" هنگام نوشتن رشته‌های متنی که قرار است روی Game Boy نمایش داده شوند، ممکن است رمزگذاری نویسه در ROM با رمزگذاری فایل منبع تفاوت داشته باشد. برای مثال، تایل‌های مورد استفاده برای حروف بزرگ ممکن است با شروع از اندیس تایل ۱۲۸ قرار گیرند، که با اسکی که از ۶۵ آغاز می‌شود متفاوت است. .Pp نگاشت‌های نویسه امکان نگاشت رشته‌ها یا لیترال‌های نویسه‌ای را به توالی‌های دلخواهی از اعداد فراهم می‌کنند: .Bd -literal -offset indent CHARMAP "A", 42 CHARMAP ':)', 39 CHARMAP "
", 13, 10 CHARMAP '€', $20ac .Ed .Pp این منجر به این می‌شود که .Ql db \(dqAmen :)
\(dq معادل با .Ql db 42, 109, 101, 110, 32, 39, 13, 10 ، و .Ql dw \(dq25€\(dq معادل با .Ql dw 50, 53, $20ac باشد. .Pp نگاشت‌های نویسه به صورت حریصانه (greedily) تطبیق داده می‌شوند، بنابراین طولانی‌ترین نگاشت قابل اعمال در یک رشته نگاشت خواهد شد. هر نویسه‌ای در رشته که بدون نگاشت تعریف‌شده باشد، مستقیماً و با استفاده از رمزگذاری نویسه‌ها به بایت‌های فایل منبع کپی خواهد شد. .Pp امکان ایجاد چندین نگاشت نویسه و سپس جابجایی بین آن‌ها بر حسب نیاز وجود دارد. برای مثال، می‌توان از این ویژگی برای رمزگذاری اطلاعات اشکال‌زدایی در اسکی و استفاده از رمزگذاری متفاوت برای اهداف دیگر استفاده کرد. در ابتدا، یک نگاشت نویسه به نام .Sq main وجود دارد و از آغاز به‌طور خودکار به عنوان نگاشت نویسه جاری انتخاب می‌شود. همچنین یک پشته نگاشت نویسه وجود دارد که می‌توان از آن برای ذخیره و بازیابی نگاشت نویسه فعال جاری استفاده کرد. .Bl -column "NEWCHARMAP name, basename" .It Sy Command Ta Sy Meaning .It Ic NEWCHARMAP Ar name Ta یک نگاشت نویسه جدید و خالی به نام Ar name ایجاد کرده و به آن سوئیچ می‌کند . .It Ic NEWCHARMAP Ar name , basename Ta یک نگاشت نویسه جدید به نام Ar name ایجاد می‌کند که از نگاشت نویسه Ar basename کپی شده است، و به آن سوئیچ می‌کند . .It Ic SETCHARMAP Ar name Ta به نگاشت نویسه Ar name سوئیچ می‌کند . .It Ic PUSHC Ta نگاشت نویسه جاری را روی پشته قرار می‌دهد (push). .It Ic PUSHC Ar name Ta نگاشت نویسه جاری را روی پشته قرار داده و به نگاشت نویسه Ar name سوئیچ می‌کند . .It Ic POPC Ta یک نگاشت نویسه را از پشته برمی‌دارد (pop) و به آن سوئیچ می‌کند. .El .Pp .Sy نکته : تغییرات اعمال‌شده روی یک نگاشت نویسه بلافاصله از همان نقطه به بعد اثرگذار خواهند بود. .Ss "سایر توابع (Other functions)" چند تابع دیگر وجود دارند که کارهایی فراتر از عملیات عددی یا رشته‌ای انجام می‌دهند: .Bl -column "SECTION(symbol)" .It Sy Name Ta Sy Operation .It Fn DEF symbol Ta اگر .Ar symbol تعریف شده باشد ۱، و در غیر این صورت ۰ برمی‌گرداند. ثابت‌های رشته‌ای درون پرانتزها بسط داده نمی‌شوند. .It Fn ISCONST arg Ta اگر مقدار Ar arg توسط RGBASM شناخته‌شده باشد ۱ (مثلاً اگر بتواند آرگومانی برای .Ic IF باشد)، یا اگر فقط RGBLINK بتواند مقدار آن را محاسبه کند ۰ برمی‌گرداند. .It Fn BANK arg Ta یک شماره بانک را برمی‌گرداند. اگر .Ar arg نماد .Ic @ باشد، این تابع بانکِ بخش جاری را برمی‌گرداند. اگر .Ar arg یک رشته باشد، بانک بخشی را که دارای آن نام است برمی‌گرداند. اگر .Ar arg یک برچسب باشد، شماره بانکی را که برچسب در آن قرار دارد برمی‌گرداند. اگر .Nm قادر به محاسبه آن باشد، حاصل ممکن است ثابت باشد. .It Fn SECTION symbol Ta نام بخشی را که .Ar symbol در آن تعریف شده است برمی‌گرداند. .Ar symbol باید پیش‌تر تعریف شده باشد. اگر .Ar arg نماد .Ic @ باشد، این تابع نام بخش جاری را برمی‌گرداند. .It Fn SIZEOF arg Ta اگر .Ar arg یک رشته باشد، این تابع اندازه بخش با نام .Ar arg را برمی‌گرداند. اگر .Ar arg یک کلیدواژه نوع بخش باشد، اندازه آن نوع بخش را برمی‌گرداند. حاصل ثابت نیست، زیرا تنها RGBLINK می‌تواند مقدار آن را محاسبه کند. اگر .Ar arg یک ثبات ۸ بیتی یا ۱۶ بیتی باشد، اندازه آن ثبات را برمی‌گرداند. .It Fn STARTOF arg Ta اگر .Ar arg یک رشته باشد، این تابع آدرس شروع بخش با نام .Ar arg را برمی‌گرداند. اگر .Ar arg یک کلیدواژه نوع بخش باشد، آدرس شروع آن نوع بخش را برمی‌گرداند. حاصل ثابت نیست، زیرا تنها RGBLINK می‌تواند مقدار آن را محاسبه کند. .El .Sh "بخش‌ها (SECTIONS)" پیش از آنکه بتوانید شروع به نوشتن کد کنید، باید یک بخش تعریف کنید. این کار به اسمبلر می‌گوید چه نوع اطلاعاتی در ادامه می‌آید و کجا باید قرار گیرد. .Pp .Dl SECTION Ar name , type .Dl SECTION Ar name , type , options .Dl SECTION Ar name , type Ns Bo Ar addr Bc .Dl SECTION Ar name , type Ns Bo Ar addr Bc , Ar options .Pp .Ar name رشته‌ای محصور در گیومه‌های دوتایی است که نام بخش می‌باشد. اگر نوع تطابق نداشته باشد، خطا رخ می‌دهد. هر بخش باید نامی یکتا داشته باشد، حتی در میان فایل‌های منبع مختلف، در غیر این صورت پیونددهنده آن را به عنوان خطا در نظر می‌گیرد. .Pp انواع .Ar type ممکن برای بخش به شرح زیر هستند: .Bl -tag -width Ds .It Ic ROM0 یک بخش ROM. .Ar addr می‌تواند از .Ad $0000 تا .Ad $3FFF ، یا از .Ad $0000 تا .Ad $7FFF در صورت فعال بودن حالت tiny ROM در پیونددهنده باشد. .It Ic ROMX یک بخش ROM بانک‌بندی‌شده (banked). .Ar addr می‌تواند از .Ad $4000 تا .Ad $7FFF باشد. در صورت فعال بودن حالت tiny ROM در پیونددهنده، به نام مستعاری برای .Ic ROM0 تبدیل می‌شود. .It Ic VRAM یک بخش رم ویدیویی (VRAM) بانک‌بندی‌شده. .Ar addr می‌تواند از .Ad $8000 تا .Ad $9FFF باشد. .Ar bank می‌تواند ۰ یا ۱ باشد، اما اگر حالت DMG در پیونددهنده فعال باشد، بانک ۱ در دسترس نیست. .It Ic SRAM یک بخش رم خارجی (ذخیره‌سازی) بانک‌بندی‌شده. .Ar addr می‌تواند از .Ad $A000 تا .Ad $BFFF باشد. .It Ic WRAM0 یک بخش رم عمومی (general-purpose RAM). .Ar addr می‌تواند از .Ad $C000 تا .Ad $CFFF ، یا از .Ad $C000 تا .Ad $DFFF در صورت فعال بودن حالت WRAM0 در پیونددهنده باشد. .It Ic WRAMX یک بخش رم عمومی بانک‌بندی‌شده. .Ar addr می‌تواند از .Ad $D000 تا .Ad $DFFF باشد. .Ar bank می‌تواند از ۱ تا ۷ باشد. در صورت فعال بودن حالت WRAM0 در پیونددهنده، به نام مستعاری برای .Ic WRAM0 تبدیل می‌شود. .It Ic OAM یک بخش رم ویژگی اشیاء (OAM). .Ar addr می‌تواند از .Ad $FE00 تا .Ad $FE9F باشد. .It Ic HRAM یک بخش رم بالا (High RAM). .Ar addr می‌تواند از .Ad $FF80 تا .Ad $FFFE باشد. .El .Pp مجموعه RGBDS رام‌ها (ROMs) را تولید می‌کند، به این معنی که کد و داده فقط می‌توانند در بخش‌های .Ic ROM0 و .Ic ROMX قرار گیرند. سایر انواع بخش‌های RAM برای برچسب‌هایی با تخصیص ایستا هستند. اگر به کد یا داده در RAM نیاز دارید، باید خودتان آن را از ROM به RAM کپی کنید. برای نمونه‌ای از چگونگی انجام راحت این کار با یک بلوک .Ic LOAD ، به .Sx RAM code مراجعه کنید. .Pp گزینه‌های .Ar option با کاما جدا می‌شوند و ممکن است شامل موارد زیر باشند: .Bl -tag -width Ds .It Ic BANK Ns Bq Ar bank مشخص می‌کند که پیونددهنده بخش را در کدام .Ar bank قرار دهد. برای مقادیر ممکن .Ar bank بسته به .Ar type ، به بالا مراجعه کنید. .It Ic ALIGN Ns Bq Ar align , offset بخش را در آدرسی قرار می‌دهد که .Ar align بیت کم‌ارزش آن برابر با .Ar offset باشند. توجه داشته باشید که .Ic ALIGN Ns Bq Ar align کوتاه‌نوشتی برای .Ic ALIGN Ns Bq Ar align , No 0 است. این گزینه می‌تواند همراه با .Bq Ar addr استفاده شود، تا زمانی که با یکدیگر تناقض نداشته باشند. همچنین می‌توان در میانه یک بخش تراز درخواست کرد؛ به .Sx Requesting alignment در ادامه مراجعه کنید. .El .Pp اگر .Bq Ar addr مشخص نشده باشد، بخش .Dq شناور (floating) در نظر گرفته می‌شود؛ پیونددهنده به‌طور خودکار آدرس مناسبی را برای بخش محاسبه خواهد کرد. به همین ترتیب، اگر .Ic BANK Ns Bq Ar bank مشخص نشده باشد، پیونددهنده به‌طور خودکار بانکی با فضای کافی پیدا خواهد کرد. .Pp بخش‌ها را می‌توان با استفاده از یک فایل اسکریپت پیونددهنده نیز مکان‌یابی کرد. قالب آن در .Xr rgblink 5 توضیح داده شده است. این اسکریپت‌ها به کاربر اجازه می‌دهند بخش‌های شناور را در بانک مورد نظر و به ترتیبی که در اسکریپت مشخص شده قرار دهد. این امر زمانی مفید است که نتوان بخش‌ها را به‌صورت دستی در یک آدرس قرار داد زیرا اندازه ممکن است تغییر کند، اما بخش‌ها باید در کنار هم باشند. .Pp مثال‌های بخش: .Bl -item .It .Bd -literal -offset indent SECTION "Cool Stuff", ROMX .Ed .Pp این دستور به بخش با نام .Dq Cool Stuff سوئیچ می‌کند و اگر از قبل وجود نداشته باشد، آن را ایجاد می‌نماید. این بخش می‌تواند در هر بانک ROM قرار گیرد. کد و داده می‌توانند پس از آن بیایند. .It در صورت نیاز، می‌توان آدرس پایه بخش را مشخص کرد: .Bd -literal -offset indent SECTION "Cool Stuff", ROMX[$4567] .Ed .It مثالی با بانک ثابت: .Bd -literal -offset indent SECTION "Cool Stuff", ROMX[$4567], BANK[3] .Ed .It و اگر بخواهید تنها بانک بخش را اجبار کنید و نه موقعیت آن در بانک را، این نیز ممکن است: .Bd -literal -offset indent SECTION "Cool Stuff", ROMX, BANK[7] .Ed .It مثال‌های ترازسازی: مورد اول می‌تواند برای تعریف یک بافر OAM که قرار است با DMA منتقل شود مفید باشد، زیرا باید در مرز ۲۵۶ بایت تراز شود. مورد دوم نیز می‌تواند برای GBC HDMA، یا برای یک کد کپی بهینه‌شده که نیازمند ترازسازی است مناسب باشد. .Bd -literal -offset indent SECTION "OAM Data", WRAM0, ALIGN[8] ;\ align to 256 bytes SECTION "VRAM Data", ROMX, BANK[2], ALIGN[4] ;\ align to 16 bytes .Ed .El .Pp بخش جاری را می‌توان بدون شروع یک بخش جدید با استفاده از .Ic ENDSECTION پایان داد. این شبه‌دستور زمینه بخش را پاک می‌کند، بنابراین تا زمانی که بخش دیگری را شروع نکنید دیگر نمی‌توانید کد بنویسید. این می‌تواند برای جلوگیری از تعریف تصادفی کد یا داده در بخش اشتباه مفید باشد. .Ss "پشته بخش (Section stack)" .Ic POPS و .Ic PUSHS رابط کار با پشته بخش را فراهم می‌کنند. تعداد ورودی‌ها در پشته تنها به میزان حافظه موجود در سیستم شما محدود می‌شود. .Pp .Ic PUSHS زمینه بخش جاری را روی پشته بخش قرار می‌دهد (push). سپس می‌توان از .Ic POPS بعداً برای بازیابی آن استفاده کرد. این ویژگی برای تعریف بخش‌ها در فایل‌های include مفید است وقتی نمی‌خواهید زمینه بخش در نقطه‌ای که فایل include شده بازنویسی شود. .Pp .Ic PUSHS همچنین می‌تواند همان آرگومان‌های .Ic SECTION را بگیرد تا زمینه بخش جاری را در پشته قرار داده و همزمان یک بخش جدید تعریف کند: .Bd -literal -offset indent SECTION "Code", ROM0 Function: ld a, 42 PUSHS "Variables", WRAM0 wAnswer: db POPS ld [wAnswer], a .Ed .Ss "کد رم (RAM code)" گاهی اوقات می‌خواهید کدی (یا داده‌ای) در RAM داشته باشید، مثلاً برای کد خودتغییردهنده (self-modifying code). اما نمی‌توانید آن را مستقیماً در یک بخش RAM قرار دهید؛ بلکه باید آن را در ROM ذخیره کرده و در نقطه‌ای از زمان به RAM کپی کنید. این بدان معنی است که کد در محدوده آدرسی متفاوت از جایی که تعریف شده اجرا خواهد شد، که این می‌تواند برای ارجاع به برچسب‌های درون آن کد ناخوشایند باشد. این وضعیت دقیقاً همان چیزی است که بلوک‌های .Ic LOAD برای آن طراحی شده‌اند. در اینجا مثالی از نحوه استفاده از آن‌ها آمده است: .Bd -literal -offset indent SECTION "LOAD example", ROMX CopyCode: ld de, RAMCode ld hl, RAMLocation ld c, RAMCode.end - RAMCode \&.loop ld a, [de] inc de ld [hli], a dec c jr nz, .loop ret RAMCode: LOAD "RAM code", WRAM0 RAMLocation: ld hl, .string ld de, $9864 \&.copy ld a, [hli] ld [de], a inc de and a jr nz, .copy ret \&.string db "Hello World!\e0" ENDL \&.end .Ed .Pp یک بلوک .Ic LOAD شبیه به اعلان .Ic SECTION به نظر می‌رسد زیرا یک بخش جدید ایجاد می‌کند. تمام داده‌ها و کدهای تولیدشده در چنین بلوکی مانند معمول در بخش جاری قرار می‌گیرند، اما تمام برچسب‌ها طوری ایجاد می‌شوند که گویی در این بخش تازه‌تأسیس قرار گرفته‌اند. .Pp در مثال بالا، تمام کدها و داده‌ها در بخش .Dq LOAD example قرار خواهند گرفت. متوجه برچسب‌های .Sq RAMCode و .Sq RAMLocation خواهید شد. اولی در ROM واقع شده است، جایی که کد ذخیره می‌شود؛ دومی در RAM قرار دارد، جایی که کد بارگذاری خواهد شد. .Pp نمی‌توانید بلوک‌های .Ic LOAD را تودرتو کنید، و همچنین نمی‌توانید بخش جاری را در درون آن‌ها تغییر دهید یا متوقف سازید. .Pp بلوک .Ic LOAD جاری را می‌توان با استفاده از .Ic ENDL پایان داد. این شبه‌دستور تنها زمانی لازم است که بخواهید نوشتن کد را در بخش ROM دربرگیرنده آن از سر بگیرید. هر یک از دستورهای .Ic LOAD ، SECTION ، ENDSECTION ، یا .Ic POPS پیش از انجام عملکرد خود، بلوک .Ic LOAD جاری را پایان خواهند داد. .Pp بلوک‌های .Ic LOAD می‌توانند از اصلاح‌کننده‌های .Ic UNION یا .Ic FRAGMENT همان‌طور که در بخش .Sx Unionized sections در ادامه شرح داده شده استفاده کنند. .Ss "بخش‌های مشترک (Unionized sections)" هنگامی که با کمبود RAM مواجه هستید، ممکن است بخواهید تخصیص‌های حافظه ایستای همپوشان تعریف کنید، همان‌طور که در بخش .Sx Allocating overlapping spaces in RAM توضیح داده شده است. با این حال، یک .Ic UNION تنها درون یک فایل منفرد کار می‌کند، بنابراین نمی‌تواند مثلاً برای تعریف متغیرهای موقت در چندین فایل استفاده شود که همگی از یک حافظه تخصیص‌یافته ایستای مشترک استفاده می‌کنند. بخش‌های مشترک (Unionized sections) این مشکل را برطرف می‌کنند. برای اعلان یک بخش مشترک، کلیدواژه .Ic UNION را بعد از کلیدواژه .Ic SECTION اضافه کنید؛ اعلان در سایر موارد تفاوتی ندارد. بخش‌های مشترک از چند قانون متفاوت نسبت به بخش‌های معمولی پیروی می‌کنند: .Bl -bullet -offset indent .It همان بخش مشترک (یعنی دارای نام یکسان) را می‌توان چندین بار در هر فراخوانی .Nm و در چندین فراخوانی اعلام کرد. با اعلان‌های مختلف به صورت یکسان رفتار شده و ادغام می‌شوند، چه در یک فراخوانی باشند یا فراخوانی‌های متفاوت. .It اگر یک بخش به عنوان مشترک اعلان شده باشد، تمام بخش‌های با همان نام نیز باید به صورت مشترک اعلان شوند. .It تمام اعلان‌ها باید نوع یکسانی داشته باشند. برای مثال، حتی اگر فلگ .Fl w دستور .Xr rgblink 1 استفاده شده باشد، انواع .Ic WRAM0 و .Ic WRAMX همچنان متفاوت در نظر گرفته می‌شوند. .It می‌توان قیدهای متفاوتی (ترازسازی، بانک و غیره) برای هر اعلان بخش مشترک تعیین کرد، اما همه آن‌ها باید سازگار باشند. برای مثال، ترازسازی باید با هر آدرس ثابتی سازگار باشد، تمام بانک‌های مشخص‌شده باید یکسان باشند، و غیره. .It بخش‌های مشترک نمی‌توانند دارای نوع .Ic ROM0 یا .Ic ROMX باشند. .El .Pp اعلان‌های مختلف از یک بخش مشترک یکسان به یکدیگر ضمیمه نمی‌شوند، بلکه درست مانند .Sx Allocating overlapping spaces in RAM بر روی یکدیگر منطبق و همپوشان می‌شوند. به همین ترتیب، اندازه یک بخش مشترک برابر با بزرگ‌ترین اندازه در میان تمام اعلان‌های آن است. .Ss "قطعات بخش (Section fragments)" قطعات بخش (Section fragments)، بخش‌هایی با یک تغییر کوچک هستند: هنگامی که چندین قطعه با یک نام یافت می‌شوند، به جای ایجاد خطا، در قالب یک بخش به هم الحاق می‌شوند، حتی در چندین فایل شیء. این امر درون یک فایل کار می‌کند (همانند رفتاری که بخش‌های «ساده» در نسخه‌های قبلی داشتند)، اما در میان فایل‌های شیء مختلف نیز کار می‌کند. برای اعلان یک قطعه بخش، کلیدواژه .Ic FRAGMENT را بعد از کلیدواژه .Ic SECTION اضافه کنید؛ اعلان در سایر موارد تفاوتی ندارد. با این حال، مشابه با .Sx Unionized sections ، باید برخی قوانین رعایت شوند: .Bl -bullet -offset indent .It اگر یک بخش به عنوان قطعه اعلان شده باشد، تمام بخش‌های با همان نام نیز باید به صورت قطعه اعلان شوند. .It تمام اعلان‌ها باید دارای نوع یکسانی باشند. برای مثال، حتی اگر فلگ .Fl w دستور .Xr rgblink 1 استفاده شده باشد، انواع .Ic WRAM0 و .Ic WRAMX همچنان متفاوت در نظر گرفته می‌شوند. .It می‌توان قیدهای متفاوتی (ترازسازی، بانک و غیره) برای هر اعلان قطعه بخش تعیین کرد، اما همه آن‌ها باید سازگار باشند. برای مثال، ترازسازی باید با هر آدرس ثابتی سازگار باشد، تمام بانک‌های مشخص‌شده باید یکسان باشند، و غیره. .It یک قطعه بخش نمی‌تواند مشترک (unionized) باشد؛ زیرا در نهایت، چنین چیزی چندان منطقی نخواهد بود. .El .Pp هنگامی که RGBASM دو قطعه را ادغام می‌کند، قطعه‌ای که دیرتر یافت شده به قطعه‌ای که زودتر یافت شده ضمیمه می‌شود. .Pp هنگامی که RGBLINK دو قطعه را ادغام می‌کند، قطعه‌ای که فایل آن در انتها مشخص شده، به قطعه‌ای که فایل آن در ابتدا مشخص شده ضمیمه می‌شود. برای مثال، با فرض اینکه .Ql bar.o ، .Ql baz.o ، و .Ql foo.o همگی حاوی قطعه‌ای با همان نام باشند، دستور .Dl rgblink -o rom.gb baz.o foo.o bar.o ابتدا قطعه حاصل از .Ql baz.o ، سپس قطعه حاصل از .Ql foo.o ، و در پایان قطعه حاصل از .Ql bar.o را تولید خواهد کرد. .Ss "لیترال‌های قطعه (Fragment literals)" لیترال‌های قطعه (Fragment literals) برای بلوک‌های کوتاهی از کد یا داده که تنها یک بار به آن‌ها ارجاع داده می‌شود مفید هستند. آن‌ها قطعات بخشی هستند که با محصور کردن دستورالعمل‌ها یا شبه‌دستورها با براکت‌های دوتایی .Ql [[ و .Ql ]] ایجاد می‌شوند، بدون نیاز به اعلان جداگانه .Ic SECTION FRAGMENT . .Pp محتوای یک لیترال قطعه تبدیل به یک .Ic SECTION FRAGMENT می‌شود، که نام و بانک یکسانی با بخش ROM والد خود به اشتراک می‌گذارد، اما بدون هیچ قید دیگری. همچنین بخش والد اگر از قبل یک قطعه نبوده باشد، به یک .Ic FRAGMENT تبدیل می‌شود، تا بتواند با لیترال‌های قطعه خود ادغام گردد. پیونددهنده RGBLINK قطعات را بدون ترتیب خاصی ادغام می‌کند. .Pp یک لیترال قطعه می‌تواند جایگزین هر ثابت عدد صحیح ۱۶ بیتی .Ql n16 از مستندات .Xr gbz80 7 و همچنین یک مورد .Ic DW شود. سپس لیترال قطعه به آدرس شروع خود ارزیابی می‌شود. برای مثال، می‌توانید به یک لیترال قطعه .Ic CALL یا .Ic JP بزنید. .Pp این کد با استفاده از برچسب‌های نام‌گذاری‌شده: .Bd -literal -offset indent DataTable: dw First dw Second dw Third First: db 1 Second: db 4 Third: db 9 Routine: push hl ld hl, Left jr z, .got_it ld hl, Right \&.got_it call .print pop hl ret \&.print: ld de, $1003 ld bc, STARTOF(VRAM) jp Print Left: db "left\e0" Right: db "right\e0" .Ed .Pp معادل با این کد با استفاده از لیترال‌های قطعه است: .Bd -literal -offset indent DataTable: dw [[ db 1 ]] dw [[ db 4 ]] dw [[ db 9 ]] Routine: push hl ld hl, [[ db "left\e0" ]] jr z, .got_it ld hl, [[ db "right\e0" ]] \&.got_it call [[ ld de, $1003 ld bc, STARTOF(VRAM) jp Print ]] pop hl ret .Ed .Pp تفاوت در این است که مثال استفاده‌کننده از لیترال‌های قطعه، ترتیب خاصی را برای اجزای خود اعلان نمی‌کند. .Pp لیترال‌های قطعه می‌توانند به دلخواه تودرتو شوند، بنابراین موارد استفاده افراطی نیز از نظر .Em فنی امکان‌پذیر است. این کد با استفاده از برچسب‌های نام‌گذاری‌شده: .Bd -literal -offset indent dw FortyTwo FortyTwo: call Sub1 jr Sub2 Sub1: ld a, [Twenty] ret Twenty: db 20 Sub2: jp Sub3 Sub3: call Sub1 inc a add a ret .Ed .Pp معادل با این کد با استفاده از لیترال‌های قطعه است: .Bd -literal -offset indent dw [[ call [[ Sub1: ld a, [ [[db 20]] ] :: ret ]] jr [[ jp [[ call Sub1 :: inc a :: add a :: ret ]] ]] ]] .Ed .Sh "نمادها (SYMBOLS)" پروژه RGBDS از چندین نوع نماد پشتیبانی می‌کند: .Bl -hang .It Sy برچسب (Label) نماد عددی که یک مکان حافظه را مشخص می‌کند. ممکن است مقداری شناخته‌شده در زمان اسمبل داشته باشد یا نداشته باشد. .It Sy ثابت (Constant) نماد عددی که مقدار آن باید در زمان اسمبل شناخته‌شده باشد. .It Sy ماکرو (Macro) بلوکی از کد .Nm که بعداً می‌تواند فراخوانی شود. .It Sy رشته (String) یک رشته متنی که بعداً می‌تواند مشابه یک ماکرو بسط داده شود. .El .Pp نام‌های نمادها می‌توانند شامل حروف اسکی، اعداد، خط زیر .Sq _ ، علامت هش .Sq # ، علامت دلار .Sq $ ، و علامت ات‌ساین .Sq @ باشند. با این حال، آن‌ها باید با یک حرف یا یک خط زیر آغاز شوند. علاوه بر این، نام‌های برچسب می‌توانند حداکثر شامل یک نقطه .Ql \&. باشند که نباید نویسه اول باشد. .Pp یک نماد نمی‌تواند همنام با یک کلمه کلیدی رزرو شده باشد، مگر اینکه نام آن یک .Dq شناسه خام با پیشوند هش .Sq # باشد. به عنوان مثال، .Ql #load نشان‌دهنده نمادی به نام .Ql load است، و .Ql #LOAD نشان‌دهنده نماد متفاوتی به نام .Ql LOAD است؛ در هر دو مورد، .Sq # از تلقی شدن آن‌ها به عنوان کلمه کلیدی .Ic LOAD جلوگیری می‌کند. .Ss "برچسب‌ها (Labels)" یکی از وظایف اصلی اسمبلر، پیگیری آدرس‌ها برای شماست، تا بتوانید به جای اعداد .Dq جادویی با نام‌های با معنی کار کنید. برچسب‌ها دقیقاً این امکان را فراهم می‌کنند: یک برچسب یک نام را به یک مکان خاص درون یک بخش پیوند می‌دهد. یک برچسب به یک بانک و آدرس ترجمه می‌شود که همزمان با بخش والد آن تعیین می‌گردد (ادامه این بخش را ببینید). .Pp یک برچسب با نوشتن نام آن در ابتدای یک خط، به همراه یک یا دو دونقطه تعریف می‌شود، بدون هیچ فاصله خالی بین نام برچسب و دونقطه(ها). تعریف یک برچسب (سراسری یا محلی) با دو دونقطه .Ql :: آن را همزمان تعریف و صادر .Pq Ic EXPORT می‌کند. (به .Sx "صادر و وارد کردن نمادها (Exporting and importing symbols)" در زیر مراجعه کنید). هنگام تعریف یک برچسب محلی، دونقطه می‌تواند حذف شود و .Nm طوری رفتار خواهد کرد که گویی تنها یک دونقطه وجود داشته است. .Pp یک برچسب در صورتی .Em محلی نامیده می‌شود که نام آن شامل یک نقطه .Ql \&. باشد؛ در غیر این صورت، .Em سراسری نامیده می‌شود (با .Dq صادر شده ، که در .Sx "صادر و وارد کردن نمادها (Exporting and importing symbols)" در زیر توضیح داده شده، اشتباه گرفته نشود). وجود بیش از یک نقطه در نام‌های برچسب مجاز نیست. .Pp برای سهولت، برچسب‌های محلی می‌توانند از نحو خلاصه استفاده کنند: زمانی که نام نمادی که با نقطه شروع می‌شود یافت شود (به عنوان مثال، درون یک عبارت یا هنگام تعریف یک برچسب)، .Dq حوزه برچسب فعلی به طور ضمنی به ابتدای آن افزوده می‌شود. .Pp تعریف یک برچسب سراسری، آن را به عنوان .Dq حوزه برچسب فعلی تنظیم می‌کند، تا زمانی که تعریف برچسب سراسری بعدی، یا پایان بخش فعلی فرا برسد. .Pp در اینجا چند مثال از تعاریف برچسب آورده شده است: .Bd -literal -offset indent GlobalLabel: AnotherGlobal: \&.locallabel ;\ This defines "AnotherGlobal.locallabel" \&.another_local: AnotherGlobal.with_another_local: ThisWillBeExported:: ;\ Note the two colons ThisWillBeExported.too:: .Ed .Pp در یک عبارت عددی، یک برچسب به آدرس خود در حافظه ارزیابی می‌شود. .Po برای به دست آوردن بانک آن، از تابع .Ql BANK() توصیف شده در .Sx Other functions استفاده کنید .Pc . به عنوان مثال، با توجه به موارد زیر، .Ql ld de, vPlayerTiles معادل .Ql ld de, $80C0 خواهد بود با فرض اینکه بخش در .Ad $80C0 قرار گیرد: .Bd -literal -offset indent SECTION "Player tiles", VRAM vPlayerTiles: ds 6 * 16 \&.end .Ed .Pp مکان یک برچسب (و در نتیجه مقدار آن) معمولاً تا مرحله پیوند تعیین نمی‌شود، بنابراین برچسب‌ها معمولاً نمی‌توانند به عنوان ثابت‌ها استفاده شوند. با این حال، اگر بخشی که برچسب در آن تعریف شده دارای یک آدرس پایه ثابت باشد، مقدار آن در زمان اسمبل مشخص است. .Pp همچنین، در حالی که .Nm بدیهی است می‌تواند تفاضل بین دو برچسب را در صورت ثابت بودن هر دو محاسبه کند، قادر است تفاضل بین دو برچسب غیرثابت را نیز در صورتی که هر دو به یک بخش تعلق داشته باشند، مانند .Ql PlayerTiles و .Ql PlayerTiles.end در بالا، محاسبه کند. .Ss "برچسب‌های ناشناس (Anonymous labels)" برچسب‌های ناشناس برای بلوک‌های کوتاه کد مفید هستند. آن‌ها مانند برچسب‌های معمولی تعریف می‌شوند، اما بدون نام قبل از دونقطه. برچسب‌های ناشناس مستقل از حوزه برچسب هستند، بنابراین تعریف یکی از آن‌ها برچسب حوزه را تغییر نمی‌دهد، و ارجاع به آن تحت تأثیر برچسب حوزه فعلی قرار نمی‌گیرد. .Pp برچسب‌های ناشناس با استفاده از یک دونقطه .Ql \&: به همراه علامت‌های مثبت .Ql + یا منفی .Ql - ارجاع داده می‌شوند. بنابراین .Ic :+ به برچسب بعدی پس از عبارت، .Ic :++ به برچسب بعد از آن؛ .Ic :- به برچسب قبلی قبل از عبارت ارجاع می‌دهد؛ و به همین ترتیب. .Bd -literal -offset indent ld hl, :++ : ld a, [hli] ; referenced by "jr nz" ldh [c], a dec c jr nz, :- ret : ; referenced by "ld hl" dw $7FFF, $1061, $03E0, $58A5 .Ed .Ss "متغیرها (Variables)" یک علامت مساوی .Sq = برای تعریف نمادهای عددی تغییرپذیر استفاده می‌شود. برخلاف سایر نمادهای توضیح داده شده در زیر، متغیرها می‌توانند دوباره تعریف شوند. این قابلیت برای نمادهای داخلی در ماکروها، شمارنده‌ها و غیره مفید است. .Bd -literal -offset indent DEF ARRAY_SIZE EQU 4 DEF COUNT = 2 DEF COUNT = 3 DEF COUNT = ARRAY_SIZE + COUNT DEF COUNT *= 2 ;\ COUNT now has the value 14 .Ed .Pp توجه داشته باشید که قرار دادن دونقطه .Ql \&: پس از نام مجاز نیست. .Pp متغیرها را می‌توان به راحتی با عملگرهای انتساب ترکیبی مانند C دوباره تعریف کرد: .Bl -column -offset indent "*= /= %=" .It Sy عملگر Ta Sy معنی .It Li += -= Ta جمع/تفریق ترکیبی .It Li *= /= %= Ta ضرب/تقسیم/باقی‌مانده ترکیبی .It Li <<= >>= Ta شیفت به چپ/راست ترکیبی .It Li &= \|= ^= Ta عملیات and/or/xor ترکیبی .El .Pp مثال‌ها: .Bd -literal -offset indent DEF x = 10 DEF x += 1 ; x == 11 DEF y = x - 1 ; y == 10 DEF y *= 2 ; y == 20 DEF y >>= 1 ; y == 10 DEF x ^= y ; x == 1 .Ed .Pp اعلان یک متغیر با .Ic EXPORT DEF یا .Ic EXPORT REDEF آن را همزمان تعریف و صادر .Pq Ic EXPORT می‌کند. (به .Sx "صادر و وارد کردن نمادها (Exporting and importing symbols)" در زیر مراجعه کنید). .Ss "ثابت‌های عددی (Numeric constants)" دستور .Ic EQU برای تعریف نمادهای ثابت عددی استفاده می‌شود. برخلاف .Sq = در بالا، ثابت‌هایی که به این روش تعریف می‌شوند را نمی‌توان دوباره تعریف کرد. این ثابت‌ها می‌توانند برای مقادیر بدون تغییر مانند ویژگی‌های سخت‌افزار استفاده شوند. .Bd -literal -offset indent def SCREEN_WIDTH equ 160 ;\ In pixels def SCREEN_HEIGHT equ 144 .Ed .Pp توجه داشته باشید که قرار دادن دونقطه .Ql \&: پس از نام مجاز نیست. .Pp اگر .Em واقعاً نیاز دارید، کلمه کلیدی .Ic REDEF یک نماد ثابت عددی را تعریف یا دوباره تعریف می‌کند. (همچنین می‌توان از آن برای متغیرها استفاده کرد، اگرچه ضروری نیست زیرا آن‌ها خود تغییرپذیر هستند.) این می‌تواند به عنوان مثال برای به‌روزرسانی یک ثابت با استفاده از یک ماکرو، بدون تغییرپذیر کردن آن در حالت کلی، استفاده شود. .Bd -literal -offset indent def NUM_ITEMS equ 0 MACRO add_item redef NUM_ITEMS equ NUM_ITEMS + 1 def ITEM_{02x:NUM_ITEMS} equ \e1 ENDM add_item 1 add_item 4 add_item 9 add_item 16 assert NUM_ITEMS == 4 assert ITEM_04 == 16 .Ed .Pp اعلان یک ثابت عددی با .Ic EXPORT DEF یا .Ic EXPORT REDEF آن را همزمان تعریف و صادر .Pq Ic EXPORT می‌کند. (به .Sx "صادر و وارد کردن نمادها (Exporting and importing symbols)" در زیر مراجعه کنید). .Ss "ثابت‌های آفست (Offset constants)" گروه دستورات RS روشی مفید برای تعریف آفست‌های ساختار است: .Bd -literal -offset indent RSRESET DEF str_pStuff RW 1 DEF str_tData RB 256 DEF str_bCount RB 1 DEF str_SIZEOF RB 0 .Ed .Pp این مثال چهار ثابت را تعریف می‌کند گویی که به شکل زیر تعریف شده باشند: .Bd -literal -offset indent DEF str_pStuff EQU 0 DEF str_tData EQU 2 DEF str_bCount EQU 258 DEF str_SIZEOF EQU 259 .Ed .Pp پنج دستور در گروه دستورات RS وجود دارد: .Bl -column "DEF name RB constexpr" .It Sy دستور Ta Sy معنی .It Ic RSRESET Ta معادل Ql RSSET 0 . .It Ic RSSET Ar constexpr Ta شمارنده Ic _RS را روی Ar constexpr تنظیم می‌کند. .It Ic DEF Ar name Ic RB Ar constexpr Ta مقدار Ar name را برابر Ic _RS قرار می‌دهد و سپس Ar constexpr را به Ic _RS اضافه می‌کند. .It Ic DEF Ar name Ic RW Ar constexpr Ta مقدار Ar name را برابر Ic _RS قرار می‌دهد و سپس Ar constexpr No * 2 را به Ic _RS اضافه می‌کند. .It Ic DEF Ar name Ic RL Ar constexpr Ta مقدار Ar name را برابر Ic _RS قرار می‌دهد و سپس Ar constexpr No * 4 را به Ic _RS اضافه می‌کند. .El .Pp اگر آرگومان .Ar constexpr برای .Ic RB ، RW ، یا .Ic RL حذف شود، مقدار آن 1 فرض می‌شود. .Pp توجه داشته باشید که قرار دادن دونقطه .Ql \&: پس از نام مجاز نیست. .Pp اعلان یک ثابت آفست با .Ic EXPORT DEF آن را همزمان تعریف و صادر .Pq Ic EXPORT می‌کند. (به .Sx "صادر و وارد کردن نمادها (Exporting and importing symbols)" در زیر مراجعه کنید). .Ss "ثابت‌های رشته‌ای (String constants)" دستور .Ic EQUS برای تعریف نمادهای ثابت رشته‌ای استفاده می‌شود. هر جا که اسمبلر یک ثابت رشته‌ای را بخواند، آن نماد .Em بسط داده می‌شود : نام نماد با محتوای آن جایگزین می‌شود، مشابه .Ic #define در زبان برنامه‌نویسی C. این بسط در چند زمینه غیرفعال است: .Ql DEF(name) ، .Ql DEF name EQU/=/EQUS/etc ... ، .Ql REDEF name EQU/=/EQUS/etc ... ، .Ql FOR name, ... ، .Ql PURGE name ، و .Ql MACRO name ثابت‌های رشته‌ای را در نام‌های خود بسط نخواهند داد. بسط همچنین در صورتی که نام ثابت رشته‌ای یک شناسه خام با پیشوند هش .Sq # باشد، غیرفعال است. .Bd -literal -offset indent DEF COUNTREG EQUS "[hl+]" ld a, COUNTREG DEF PLAYER_NAME EQUS "\e"John\e"" db PLAYER_NAME .Ed .Pp این به صورت زیر تفسیر خواهد شد: .Bd -literal -offset indent ld a, [hl+] db "John" .Ed .Pp ثابت‌های رشته‌ای همچنین می‌توانند برای تعریف ماکروهای کوچک تک‌خطی استفاده شوند: .Bd -literal -offset indent DEF pusha EQUS "push af\enpush bc\enpush de\enpush hl\en" .Ed .Pp توجه داشته باشید که قرار دادن دونقطه .Ql \&: پس از نام مجاز نیست. .Pp ثابت‌های رشته‌ای، مانند ثابت‌های عددی، نمی‌توانند دوباره تعریف شوند. با این حال، کلمه کلیدی .Ic REDEF یک نماد ثابت رشته‌ای را تعریف یا دوباره تعریف می‌کند. به عنوان مثال: .Bd -literal -offset indent DEF s EQUS "Hello, " REDEF s EQUS "{s}world!" ; prints "Hello, world!" PRINTLN "{s}\en" .Ed .Pp ثابت‌های رشته‌ای را نمی‌توان صادر یا وارد کرد. .Pp .Sy نکته مهم : هنگامی که یک ثابت رشته‌ای بسط داده می‌شود، بسط آن ممکن است شامل ثابت رشته‌ای دیگری باشد که آن نیز بسط داده خواهد شد و ممکن است بازگشتی باشد. اگر این امر یک حلقه بی‌نهایت ایجاد کند، .Nm پس از رسیدن به یک عمق معین با خطا متوقف می‌شود (گزینه خط فرمان .Fl r در .Xr rgbasm 1 را ببینید). همین مشکل در صورتی که بسط یک ثابت رشته‌ای ماکرویی را فراخوانی کند که خود بسط می‌یابد، می‌تواند رخ دهد. .Ss "ماکروها (Macros)" یکی از بهترین ویژگی‌های یک اسمبلر توانایی نوشتن ماکروها برای آن است. ماکروها را می‌توان با آرگومان‌ها فراخوانی کرد و آن‌ها می‌توانند بسته به ورودی با استفاده از ساختارهای .Ic IF واکنش نشان دهند. .Bd -literal -offset indent MACRO my_macro ld a, 80 call MyFunc ENDM .Ed .Pp مثال بالا .Ql my_macro را به عنوان یک ماکروی جدید تعریف می‌کند. ثابت‌های رشته‌ای در نام ماکرو بسط داده نمی‌شوند. .Pp ماکروها را نمی‌توان صادر یا وارد کرد. .Pp تودرتو کردن تعاریف ماکرو امکان‌پذیر نیست، بنابراین این مورد کار نخواهد کرد: .Bd -literal -offset indent MACRO outer MACRO inner PRINTLN "Hello!" ENDM ; this actually ends the 'outer' macro... ENDM ; ...and then this is a syntax error! .Ed .Pp اما می‌توانید با استفاده از .Ic EQUS این محدودیت را دور بزنید، بنابراین این مورد کار خواهد کرد: .Bd -literal -offset indent MACRO outer DEF definition EQUS "MACRO inner\enPRINTLN \e"Hello!\e"\enENDM" definition PURGE definition ENDM .Ed .Pp اطلاعات بیشتر درباره نحوه تعریف و فراخوانی ماکروها در .Sx "زبان ماکرو (THE MACRO LANGUAGE)" در زیر توضیح داده شده است. .Ss "صادر و وارد کردن نمادها (Exporting and importing symbols)" وارد و صادر کردن نمادها قابلیتی است که وقتی پروژه شما چندین فایل منبع را در بر می‌گیرد، بسیار مفید است؛ به عنوان مثال، زمانی که نیاز دارید به روال تعریف‌شده در فایل دیگری پرش کنید. .Pp صادر کردن نمادها باید به صورت دستی انجام شود، در حالی که وارد کردن در صورتی که .Nm نمادی را پیدا کند که از آن اطلاعی ندارد به صورت خودکار انجام می‌شود. .Pp دستور زیر باعث می‌شود .Ar symbol1 ، symbol2 و غیره در طول فرآیند پیوند برای فایل‌های دیگر قابل دسترسی باشند: .Dl Ic EXPORT Ar symbol1 Bq , Ar symbol2 , No ... .Pp به عنوان مثال، اگر سه فایل زیر را داشته باشید: .Pp .Ql a.asm : .Bd -literal -offset indent -compact SECTION "a", WRAM0 LabelA: .Ed .Pp .Ql b.asm : .Bd -literal -offset indent -compact SECTION "b", WRAM0 ExportedLabelB1:: ExportedLabelB2: EXPORT ExportedLabelB2 .Ed .Pp .Ql c.asm : .Bd -literal -offset indent -compact SECTION "C", ROM0[0] dw LabelA dw ExportedLabelB1 dw ExportedLabelB2 .Ed .Pp آنگاه .Ql c.asm می‌تواند از .Ql ExportedLabelB1 و .Ql ExportedLabelB2 استفاده کند، اما نمی‌تواند از .Ql LabelA استفاده کند، بنابراین پیوند دادن آن‌ها با یکدیگر شکست خواهد خورد: .Bd -literal -offset indent $ rgbasm -o a.o a.asm $ rgbasm -o b.o b.asm $ rgbasm -o c.o c.asm $ rgblink a.o b.o c.o error: Undefined symbol "LabelA" at c.asm(2) Linking failed with 1 error .Ed .Ss "پاک‌سازی نمادها (Purging symbols)" دستور .Ic PURGE به شما امکان می‌دهد یک نماد را کاملاً از جدول نمادها حذف کنید، گویی که هرگز تعریف نشده است. .Bd -literal -offset indent DEF value EQU 42 PURGE value DEF value EQUS "I'm a string now" ASSERT DEF(value) PURGE value ASSERT !DEF(value) .Ed .Pp هنگام پاک‌سازی نمادهایی که در داده‌های بخش ارجاع داده شده‌اند، یا صادر شده‌اند، .Em بسیار مراقب باشید، زیرا اگر چیزی به نماد گمشده وابسته باشد (به عنوان مثال، عباراتی که پیونددهنده نیاز به محاسبه آن‌ها دارد)، ممکن است منجر به خطاهای غیرقابل پیش‌بینی شود. پاک‌سازی برچسب‌ها به هیچ وجه توصیه .Em نمی‌شود . .Pp ثابت‌های رشته‌ای درون نام‌های نماد بسط داده نمی‌شوند. .Ss "نمادهای از پیش تعریف‌شده (Predeclared symbols)" نمادهای زیر توسط اسمبلر تعریف شده‌اند: .Bl -column -offset indent "__ISO_8601_LOCAL__" "EQUS" .It Sy نام Ta Sy نوع Ta Sy محتویات .It Dv @ Ta Ic EQU Ta مقدار PC (اساساً، آدرس حافظه فعلی) .It Dv . Ta Ic EQUS Ta حوزه برچسب سراسری فعلی .It Dv .. Ta Ic EQUS Ta حوزه برچسب محلی فعلی .It Dv __SCOPE__ Ta Ic EQUS Ta درونی‌ترین سطح حوزه برچسب فعلی (خالی، "."، یا "..") .It Dv _RS Ta Ic = Ta شمارنده _RS .It Dv _NARG Ta Ic EQU Ta تعداد آرگومان‌های ارسالی به ماکرو، به‌روزرسانی شده توسط Ic SHIFT .It Dv __ISO_8601_LOCAL__ Ta Ic EQUS Ta برچسب زمانی ISO 8601 (محلی) .It Dv __ISO_8601_UTC__ Ta Ic EQUS Ta برچسب زمانی ISO 8601 (UTC) .It Dv __UTC_YEAR__ Ta Ic EQU Ta سال جاری .It Dv __UTC_MONTH__ Ta Ic EQU Ta شماره ماه جاری، 1\[en]12 .It Dv __UTC_DAY__ Ta Ic EQU Ta روز جاری از ماه، 1\[en]31 .It Dv __UTC_HOUR__ Ta Ic EQU Ta ساعت فعلی، 0\[en]23 .It Dv __UTC_MINUTE__ Ta Ic EQU Ta دقیقه فعلی، 0\[en]59 .It Dv __UTC_SECOND__ Ta Ic EQU Ta ثانیه فعلی، 0\[en]59 .It Dv __RGBDS_MAJOR__ Ta Ic EQU Ta شماره نسخه اصلی RGBDS .It Dv __RGBDS_MINOR__ Ta Ic EQU Ta شماره نسخه فرعی RGBDS .It Dv __RGBDS_PATCH__ Ta Ic EQU Ta شماره نسخه وصله RGBDS .It Dv __RGBDS_RC__ Ta Ic EQU Ta شناسه نامزد انتشار RGBDS، برای نسخه‌های نهایی تعریف نشده است .It Dv __RGBDS_VERSION__ Ta Ic EQUS Ta نسخه RGBDS، همانطور که توسط Ql rgbasm --version چاپ می‌شود .El .Pp مقادیر زمان فعلی از متغیر محیطی .Dv SOURCE_DATE_EPOCH در صورتی که به عنوان یک برچسب زمانی یونیکس تعریف شده باشد، گرفته خواهد شد. به مشخصات در .Lk https://reproducible-builds.org/docs/source-date-epoch reproducible-builds.org مراجعه کنید. .Sh "تعریف داده‌ها (DEFINING DATA)" .Ss "تعریف داده‌های ثابت در ROM (Defining constant data in ROM)" دستور .Ic DB فهرستی از بایت‌ها را تعریف می‌کند که در تصویر نهایی ذخیره خواهند شد. ایده‌آل برای جدول‌ها و متن. .Bd -literal -offset indent DB 1,2,3,4,"This is a string" .Ed .Pp همچنین، می‌توانید از .Ic DW برای ذخیره فهرستی از کلمات (16 بیتی) یا از .Ic DL برای ذخیره فهرستی از کلمات مضاعف/طولانی (32 بیتی) استفاده کنید. هر دوی این دستورات داده‌های خود را با ترتیب بایت اندیان کوچک (little-endian) می‌نویسند؛ به عنوان مثال، .Ql dw $CAFE معادل .Ql db $FE, $CA است و نه .Ql db $CA, $FE . .Pp رشته‌ها تا حدودی به طور ویژه مدیریت می‌شوند: آن‌ها ابتدا تحت تبدیل نگاشت نویسه قرار می‌گیرند (به .Sx "Character maps" مراجعه کنید)، سپس هر نویسه حاصل به صورت مجزا خروجی داده می‌شود. به عنوان مثال، تحت نگاشت نویسه پیش‌فرض، دو خط زیر یکسان هستند: .Bd -literal -offset indent DW "Hello!" DW "H", "e", "l", "l", "o", "!" .Ed .Pp اگر این رفتار ویژه را نمی‌خواهید، رشته را در پرانتز قرار دهید. .Pp دستور .Ic DS همچنین می‌تواند برای پر کردن ناحیه‌ای از حافظه با مقادیر تکراری استفاده شود. به عنوان مثال: .Bd -literal -offset indent ; outputs 3 bytes: $AA, $AA, $AA DS 3, $AA ; outputs 7 bytes: $BB, $CC, $BB, $CC, $BB, $CC, $BB DS 7, $BB, $CC .Ed .Pp همچنین می‌توانید از .Ic DB ، DW و .Ic DL بدون آرگومان استفاده کنید. این دقیقاً مانند .Ic DS 1 ، DS 2 و .Ic DS 4 به ترتیب عمل می‌کند. در نتیجه، .Ic DB ، DW و .Ic DL بدون آرگومان را می‌توان در بخش‌های .Ic WRAM0 / .Ic WRAMX / .Ic HRAM / .Ic VRAM / .Ic SRAM استفاده کرد. .Ss "شامل کردن فایل‌های داده دودویی (Including binary data files)" شما احتمالاً داده‌های گرافیکی، مراحل بازی و غیره دارید که مایلید آن‌ها را شامل کنید. از .Ic INCBIN برای شامل کردن یک فایل دودویی خام همان‌طور که هست استفاده کنید. اگر فایل در دایرکتوری فعلی یافت نشود، فهرست مسیرهای شامل‌سازی ارائه‌شده به گزینه .Fl I دستور .Xr rgbasm 1 در خط فرمان جستجو خواهد شد. .Bd -literal -offset indent INCBIN "titlepic.bin" INCBIN "sprites/hero.bin" .Ed .Pp همچنین می‌توانید تنها بخشی از یک فایل را با .Ic INCBIN شامل کنید. مثال زیر 256 بایت از data.bin را با شروع از بایت 78 شامل می‌کند. .Bd -literal -offset indent INCBIN "data.bin", 78, 256 .Ed .Pp آرگومان طول اختیاری است. اگر تنها موقعیت شروع مشخص شود، بایت‌ها از موقعیت شروع تا انتهای فایل شامل خواهند شد. .Ss "تخصیص ایستا فضا در RAM (Statically allocating space in RAM)" دستور .Ic DS تعداد مشخصی بایت خالی را به صورت ایستا تخصیص می‌دهد. این روش ترجیحی برای تخصیص فضا در یک بخش RAM است. همچنین می‌توانید به جای آن از .Ic DB ، DW و .Ic DL بدون هیچ آرگومانی استفاده کنید (به .Sx "تعریف داده‌های ثابت در ROM (Defining constant data in ROM)" در زیر مراجعه کنید). .Bd -literal -offset indent DS 42 ;\ Allocates 42 bytes .Ed .Pp فضای خالی در بخش‌های RAM مقداردهی اولیه نخواهد شد. در بخش‌های ROM، با مقدار ارسال‌شده به گزینه خط فرمان .Fl p پر خواهد شد، به جز هنگام استفاده از هم‌پوشانی‌ها با .Fl O . .Pp به جای تعداد دقیق بایت‌ها، می‌توانید .Ic ALIGN Ns Bq Ar align , offset را مشخص کنید تا هر تعداد بایت که برای تراز کردن داده‌های بعدی لازم است تخصیص یابد. بنابراین، .Sq Ic DS ALIGN Ns Bo Ar align , offset Bc , No ... معادل .Sq Ic DS Ar n , No ... به دنبال .Sq Ic ALIGN Ns Bq Ar align , offset است، که در آن .Ar n حداقل مقدار مورد نیاز برای برآورده کردن محدودیت .Ic ALIGN است (به .Sx "درخواست تراز (Requesting alignment)" در زیر مراجعه کنید). توجه داشته باشید که .Ic ALIGN Ns Bq Ar align کوتاه‌شده‌ای برای .Ic ALIGN Ns Bq Ar align , No 0 است. .Ss "تخصیص فضاهای همپوشا در RAM (Allocating overlapping spaces in RAM)" یونیون‌ها به چندین تخصیص حافظه ایستا اجازه همپوشانی می‌دهند، مانند union در زبان C. این امر مقدار حافظه در دسترس را افزایش نمی‌دهد، اما اجازه می‌دهد از همان ناحیه حافظه برای اهداف مختلف دوباره استفاده شود. .Pp یک یونیون با کلمه کلیدی .Ic UNION شروع می‌شود و با کلمه کلیدی متناظر .Ic ENDU پایان می‌یابد. دستور .Ic NEXTU هر بلوک از تخصیص‌ها را جدا می‌کند، و می‌توانید هر تعداد بار که در یک یونیون لازم است از آن استفاده کنید. .Bd -literal -offset indent ; Let's say PC == $C0DE here UNION ; Here, PC == $C0DE wName:: ds 10 ; Now, PC == $C0E8 wNickname:: ds 10 ; PC == $C0F2 NEXTU ; PC is back to $C0DE wHealth:: dw ; PC == $C0E0 wLives:: db ; PC == $C0E1 ds 7 ; PC == $C0E8 wBonus:: db ; PC == $C0E9 NEXTU ; PC is back to $C0DE again wVideoBuffer: ds 16 ; PC == $C0EE ENDU ; Afterward, PC == $C0F2 .Ed .Pp در مثال بالا، .Sq wName ، wHealth ، و .Sq wVideoBuffer همگی مقدار یکسانی دارند؛ همینطور .Sq wNickname و .Sq wBonus . بنابراین به خاطر داشته باشید که .Ql ld [wHealth], a دقیقاً به همان دستور .Ql ld [wName], a اسمبل می‌شود. .Pp اندازه کل این یونیون 20 بایت است، یعنی اندازه بزرگترین بلوک (اولین بلوک، شامل .Sq wName و .Sq wNickname ) . .Pp یونیون‌ها ممکن است تودرتو باشند، به طوری که اندازه هر یونیون درونی طبق روش بالا تعیین می‌شود و مانند هر تخصیص دیگری روی یونیون بیرونی تأثیر می‌گذارد. .Pp یونیون‌ها را می‌توان در هر بخشی استفاده کرد، اما آن‌ها فقط می‌توانند شامل دستورالعمل‌های تخصیص فضا مانند .Ic DS باشند (به .Sx "تخصیص ایستا فضا در RAM (Statically allocating space in RAM)" مراجعه کنید). .Ss "درخواست تراز (Requesting alignment)" در حالی که دستور .Ic ALIGN همانطور که در .Sx SECTIONS معرفی شد اغلب به همان شکل مفید است، گاهی اوقات به جای آن می‌خواهید یک قطعه داده (یا کد) خاص در میانه بخش تراز شود. این کار از طریق استفاده از .Ic ALIGN Ar align , offset در میانه بخش آسان‌تر شده است. این دستور ویژگی‌های بخش را عطف‌به‌ماسبق تغییر می‌دهد تا اطمینان حاصل شود مکانی که دستورالعمل .Ic ALIGN در آن قرار دارد، .Ar align بیت پایین‌تر آن برابر با .Ar offset باشد. .Pp اگر این محدودیت نتواند برآورده شود (برای مثال به دلیل اینکه بخش در یک آدرس ناسازگار ثابت شده است)، خطایی ایجاد می‌شود. توجه داشته باشید که .Ic ALIGN Ar align کوتاه‌شده‌ای برای .Ic ALIGN Ar align , No 0 است. .Pp ممکن است زمان‌هایی وجود داشته باشد که نه‌تنها بخواهید یک محدودیت تراز را در مکان فعلی مشخص کنید، بلکه بخواهید تا زمانی که محدودیت برآورده شود به جلو بروید. در این حالت، می‌توانید از .Ic DS ALIGN Ns Bq Ar align , offset برای تخصیص هر تعداد بایت که برای تراز کردن داده‌های بعدی لازم است استفاده کنید. .Pp اگر با پرش از هر مقدار فضا نتوان محدودیت را برآورده کرد، خطایی ایجاد می‌شود. توجه داشته باشید که .Ic ALIGN Ns Bq Ar align کوتاه‌شده‌ای برای .Ic ALIGN Ns Bq Ar align , No 0 است. .Sh "زبان ماکرو (THE MACRO LANGUAGE)" .Ss "فراخوانی ماکروها (Invoking macros)" یک ماکرو با استفاده از نام آن در ابتدای یک خط، مانند یک دستورالعمل، به همراه هر آرگومان جدا شده با ویرگول فراخوانی می‌شود. .Bd -literal -offset indent add a, b ld sp, hl my_macro ;\ This will be expanded sub a, 87 my_macro 42 ;\ So will this ret c my_macro 1, 2 ;\ And this .Ed .Pp پس از اینکه .Nm خط فراخوانی ماکرو را خواند، بدنه ماکرو (خطوط بین .Ic MACRO و .Ic ENDM ) را در جای آن بسط می‌دهد. .Pp .Sy نکته مهم : هنگامی که بدنه یک ماکرو بسط می‌یابد، بسط آن ممکن است شامل فراخوانی ماکروی دیگری باشد که آن نیز بسط داده خواهد شد و ممکن است بازگشتی باشد. اگر این امر یک حلقه بی‌نهایت ایجاد کند، .Nm پس از رسیدن به یک عمق معین با خطا متوقف می‌شود (گزینه خط فرمان .Fl r در .Xr rgbasm 1 را ببینید). همین مشکل ممکن است در صورتی که بسط یک ماکرو سپس یک ثابت رشته‌ای را بسط دهد که خود بسط می‌یابد، رخ دهد. .Pp ارسال آرگومان‌ها به ماکروها نیز امکان‌پذیر است! .Bd -literal -offset indent MACRO lb ld \e1, (\e2) << 8 | (\e3) ENDM lb hl, 20, 18 ; Expands to "ld hl, ((20) << 8) | (18)" lb de, 3 + 1, NUM**2 ; Expands to "ld de, ((3 + 1) << 8) | (NUM**2)" .Ed .Pp شما آرگومان‌ها را درون بدنه ماکرو با استفاده از دنباله‌های گریز .Ic \e1 تا .Ic \e9 بسط می‌دهید؛ .Ic \e1 اولین آرگومان است، .Ic \e2 دومین آرگومان، و به همین ترتیب. از آنجا که تنها نه رقم وجود دارد، شما فقط می‌توانید از نه آرگومان اول ماکرو به این شکل استفاده کنید. برای استفاده از بقیه، شماره آرگومان را در قلاب‌های شکسته قرار می‌دهید، مانند .Ic \e<10> . .Pp این نحو قلاب‌دار از اعداد ده‌دهی و نمادهای عددی پشتیبانی می‌کند، جایی که مقادیر منفی از آخرین آرگومان شمارش می‌شوند. به عنوان مثال، .Ql \e<_NARG> یا .Ql \e<-1> آخرین آرگومان را دریافت خواهد کرد. .Pp سایر آرگومان‌های ماکرو و درون‌یابی‌های نماد نیز درون قلاب‌های شکسته بسط داده خواهند شد. به عنوان مثال، اگر .Ql \e1 برابر با .Ql 13 باشد، آنگاه .Ql \e<\e1> درون بدنه ماکرو به .Ql \e<13> بسط می‌یابد. یا اگر .Ql DEF v10 = 42 و .Ql DEF x = 10 باشد، آنگاه .Ql \e به .Ql \e<42> بسط خواهد یافت. .Pp آرگومان‌های ماکرو به صورت ثابت‌های رشته‌ای ارسال می‌شوند، اگرچه نیازی به قرار دادن آن‌ها درون علامت نقل‌قول نیست. بنابراین، آرگومان‌ها به عنوان عبارت ارزیابی نمی‌شوند، بلکه مستقیماً درون بدنه ماکرو بسط می‌یابند. این بدان معنی است که آن‌ها از تمام دنباله‌های گریز رشته‌ها پشتیبانی می‌کنند (به .Sx String expressions در بالا مراجعه کنید)، و همچنین برخی از دنباله‌های خاص خود را دارند: .Bl -column -offset indent "Sequence" .It Sy دنباله Ta Sy معنی .It Ql \e, Ta ویرگول Pq آرگومان را خاتمه نمی‌دهد .It Ql \e( Ta پرانتز باز Pq محتوای آرگومان را محصور نمی‌کند .It Ql \e) Ta پرانتز بسته Pq محتوای آرگومان را خاتمه نمی‌دهد .El .Pp ادامه‌های خط طبق معمول درون ماکروها یا فهرست‌های آرگومان ماکرو کار می‌کنند. با این حال، برخی از نویسه‌ها باید گریز داده شوند، همانطور که در مثال زیر آمده است: .Bd -literal -offset indent MACRO PrintMacro1 PRINTLN STRCAT(\e1) ENDM PrintMacro1 "Hello "\e, \e "world" MACRO PrintMacro2 PRINT \e1 ENDM PrintMacro2 STRCAT("Hello ", \e "world\en") .Ed .Pp ویرگول در .Ql PrintMacro1 باید گریز داده شود تا از شروع یک آرگومان ماکروی دیگر جلوگیری کند. ویرگول در .Ql PrintMacro2 نیازی به گریز ندارد زیرا داخل پرانتز است، مشابه آرگومان‌های ماکرو در زبان برنامه‌نویسی C. بک‌اسلش در .Ql \en نیز نیازی به گریز ندارد زیرا لیترال‌های رشته‌ای نقل‌قول‌شده طبق معمول درون آرگومان‌های ماکرو کار می‌کنند. .Pp از آنجا که آرگومان‌های ماکرو مستقیماً بسط می‌یابند، اغلب ایده خوبی است که اگر قرار است بخشی از یک عبارت عددی باشند، آن‌ها را درون پرانتز قرار دهید. برای نمونه، موارد زیر را در نظر بگیرید: .Bd -literal -offset indent MACRO print_double PRINTLN \e1 * 3 ENDM print_double 1 + 2 .Ed .Pp بدنه به .Ql PRINTLN 1 + 2 * 3 بسط خواهد یافت که مقدار 7 را چاپ می‌کند و نه 9 همانطور که ممکن است انتظار داشته باشید. .Pp دستورالعمل .Ic SHIFT فقط درون بدنه ماکروها در دسترس است. این دستور شماره‌های آرگومان را یک واحد به سمت چپ منتقل می‌کند، بنابراین آنچه .Ic \e2 بود اکنون .Ic \e1 است، آنچه .Ic \e3 بود اکنون .Ic \e2 است، و به همین ترتیب. (آنچه .Ic \e1 بود دیگر در دسترس نیست، بنابراین .Dv _NARG به اندازه 1 کاهش می‌یابد.) .Pp دستور .Ic SHIFT همچنین می‌تواند یک پارامتر عدد صحیح بگیرد تا به جای یک بار، به آن تعداد دفعات شیفت را انجام دهد. یک پارامتر منفی آرگومان‌ها را به سمت راست شیفت می‌دهد که می‌تواند دسترسی به موارد شیفت‌داده‌شده قبلی را دوباره به دست آورد. .Pp دستور .Ic SHIFT به ویژه در حلقه‌های .Ic REPT برای تکرار روی آرگومان‌های مختلف و ارزیابی همان بدنه حلقه در هر بار بسیار مفید است. .Pp چندین دنباله گریز وجود دارند که فقط درون بدنه یک ماکرو معتبر هستند: .Bl -column -offset indent "Sequence" .It Sy دنباله Ta Sy معنی .It So \e1 Sc \[en] So \e9 Sc Ta آرگومان‌های اول\[en]نهم ماکرو .It Ql \e<...> Ta آرگومان‌های بعدی ماکرو .It Ql \e# Ta همه آرگومان‌های Dv _NARG ماکرو، جدا شده با ویرگول .It Ql \e@ Ta پسوند نام نماد یکتا Pq زیر را ببینید .El .Pp دنباله گریز .Ic \e@ اغلب در ماکروهایی که نمادها را تعریف می‌کنند مفید است. فرض کنید ماکروی شما به یک حلقه از کد اسمبلی بسط می‌یابد: .Bd -literal -offset indent MACRO loop_c_times xor a, a \&.loop ld [hl+], a dec c jr nz, .loop ENDM .Ed .Pp اگر از این ماکرو بیش از یک بار در همان حوزه برچسب استفاده کنید، .Ql \&.loop را دو بار تعریف می‌کند که یک خطا است. برای رفع این مشکل، می‌توانید از .Ic \e@ به عنوان پسوند برچسب استفاده کنید: .Bd -literal -offset indent MACRO loop_c_times_fixed xor a, a \&.loop\e@ ld [hl+], a dec c jr nz, .loop\e@ ENDM .Ed .Pp این در هر فراخوانی به مقدار متفاوتی بسط می‌یابد، مشابه .Ic gensym در زبان برنامه‌نویسی Lisp. .Pp همچنین .Ic \e@ در بلوک‌های .Ic REPT کار می‌کند، و در هر تکرار به مقدار متفاوتی بسط می‌یابد. .Ss "تکرار خودکار بلوک‌های کد (Automatically repeating blocks of code)" فرض کنید می‌خواهید یک حلقه وقت‌گیر را بدون کپی و چسباندن آن باز کنید (unroll کنید). دستور .Ic REPT برای این منظور فراهم شده است. همه چیز بین .Ic REPT و .Ic ENDR متناظر، به تعداد مشخصی تکرار خواهد شد، درست مانند اینکه خودتان عملیات کپی/چسباندن را انجام داده باشید. مثال زیر .Ql add a, c را چهار بار اسمبل می‌کند: .Bd -literal -offset indent REPT 4 add a, c ENDR .Ed .Pp همچنین می‌توانید از .Ic REPT برای تولید جدول‌ها به صورت بلادرنگ استفاده کنید: .Bd -literal -offset indent ; Generate a table of square values from 0**2 = 0 to 100**2 = 10000 DEF x = 0 REPT 101 dw x * x DEF x += 1 ENDR .Ed .Pp همانند ماکروها، می‌توانید از دنباله گریز .Ic \e@ نیز استفاده کنید. بلوک‌های .Ic REPT می‌توانند تودرتو باشند. .Pp یک الگوی رایج، تکرار یک بلوک به ازای هر مقدار در یک محدوده خاص است. دستور .Ic FOR برای این هدف ساده‌تر از .Ic REPT است. همه چیز بین .Ic FOR و .Ic ENDR متناظر برای هر مقدار از یک نماد داده‌شده تکرار خواهد شد. ثابت‌های رشته‌ای درون نام نماد بسط داده نمی‌شوند. به عنوان مثال، این کد جدولی از مقادیر مربع از 0 تا 255 تولید می‌کند: .Bd -literal -offset indent FOR N, 256 dw N * N ENDR .Ed .Pp این دستور دقیقاً طوری عمل می‌کند که گویی چنین کدی نوشته‌اید: .Bd -literal -offset indent DEF N = 0 dw N * N DEF N = 1 dw N * N DEF N = 2 dw N * N ; ... DEF N = 255 dw N * N DEF N = 256 .Ed .Pp می‌توانید محدوده مقادیر .Ic FOR را سفارشی کنید، مشابه تابع .Ql range در زبان برنامه‌نویسی Python: .Bl -column "FOR V, start, stop, step" .It Sy کد Ta Sy محدوده .It Ic FOR Ar V , stop Ta Ar V از 0 تا Ar stop افزایش می‌یابد .It Ic FOR Ar V , start , stop Ta Ar V از Ar start تا Ar stop افزایش می‌یابد .It Ic FOR Ar V , start , stop , step Ta Ar V از Ar start تا Ar stop با گام Ar step پیش می‌رود .El .Pp مقدار .Ic FOR با .Ar step به‌روزرسانی می‌شود تا زمانی که به .Ar stop برسد یا از آن فراتر رود، یعنی محدوده نیمه‌باز از .Ar start (شامل) تا .Ar stop (غیرشامل) را پوشش می‌دهد. متغیر .Ar V در ابتدای هر تکرار جدید به این مقدار اختصاص می‌یابد؛ هرگونه تغییری که در بدنه حلقه .Ic FOR در آن ایجاد شود بازنویسی خواهد شد. بنابراین نماد .Ar V لازم نیست قبل از هر تکرار حلقه .Ic FOR از قبل تعریف شده باشد، اما اگر تعریف شده باشد باید یک متغیر .Pq Sx "متغیرها (Variables)" باشد. به عنوان مثال: .Bd -literal -offset indent FOR V, 4, 25, 5 PRINT "{d:V} " DEF V *= 2 ENDR PRINTLN "done {d:V}" .Ed .Pp این قطعه کد خروجی زیر را چاپ می‌کند: .Bd -literal -offset indent 4 9 14 19 24 done 29 .Ed .Pp درست مانند بلوک‌های .Ic REPT ، می‌توانید از دنباله گریز .Ic \e@ درون بلوک‌های .Ic FOR استفاده کنید، و آن‌ها می‌توانند تودرتو باشند. .Pp می‌توانید یک بلوک تکرار را با دستور .Ic BREAK متوقف کنید. دستور .Ic BREAK درون یک بلوک .Ic REPT یا .Ic FOR تکرار فعلی را قطع می‌کند و دیگر تکرار نخواهد شد. این دستور اجرای کد را پس از .Ic ENDR بلوک ادامه خواهد داد. به عنوان مثال: .Bd -literal -offset indent FOR V, 1, 100 PRINT "{d:V}" IF V == 5 PRINT " stop! " BREAK ENDC PRINT ", " ENDR PRINTLN "done {d:V}" .Ed .Pp این خروجی زیر را چاپ می‌کند: .Bd -literal -offset indent 1, 2, 3, 4, 5 stop! done 5 .Ed .Ss "اسمبل شرطی بلوک‌های کد (Conditionally assembling blocks of code)" چهار دستور .Ic IF ، ELIF ، ELSE ، و .Ic ENDC به شما امکان می‌دهند بسته به یک شرط، بخش‌هایی از کد خود را توسط .Nm نادیده بگیرید. این یک قابلیت قدرتمند است که معمولاً در ماکروها استفاده می‌شود. .Bd -literal -offset indent IF NUM < 0 PRINTLN "NUM < 0" ELIF NUM == 0 PRINTLN "NUM == 0" ELSE PRINTLN "NUM > 0" ENDC .Ed .Pp بلوک‌های .Ic ELIF (کوتاه‌شده "else if") و .Ic ELSE اختیاری هستند. بلوک‌های .Ic IF / .Ic ELIF / .Ic ELSE / .Ic ENDC می‌توانند تودرتو باشند. .Pp توجه داشته باشید که اگر یک بلوک .Ic ELSE قبل از یک بلوک .Ic ELIF یافت شود، بلوک .Ic ELIF نادیده گرفته خواهد شد. تمام بلوک‌های .Ic ELIF باید قبل از بلوک .Ic ELSE قرار گیرند. همچنین، اگر بیش از یک بلوک .Ic ELSE وجود داشته باشد، همه آن‌ها به جز اولین مورد نادیده گرفته می‌شوند. .Ss "شامل کردن سایر فایل‌های منبع (Including other source files)" از .Ic INCLUDE برای پردازش یک فایل اسمبلی دیگر و سپس بازگشت به فایل فعلی پس از اتمام استفاده کنید. اگر فایل در دایرکتوری فعلی یافت نشود، فهرست مسیرهای شامل‌سازی ارائه‌شده به گزینه .Fl I دستور .Xr rgbasm 1 در خط فرمان جستجو خواهد شد. شما می‌توانید فراخوانی‌های .Ic INCLUDE را به صورت نامحدود تودرتو کنید (یا تا زمانی که حافظه تمام شود، هر کدام که زودتر رخ دهد). .Bd -literal -offset indent INCLUDE "irq.inc" .Ed .Pp همچنین می‌توانید قبل از فایل منبع، فایلی را به طور ضمنی با استفاده از گزینه .Fl P در .Xr rgbasm 1 شامل .Pq Ic INCLUDE کنید. .Ss "چاپ موارد هنگام اسمبل (Printing things during assembly)" دستورات .Ic PRINT و .Ic PRINTLN متن و مقادیر را در خروجی استاندارد چاپ می‌کنند. برای اشکال‌زدایی ماکروها یا هر جایی که احساس نیاز به اعلام اطلاعات مهمی به خود داشته باشید مفید است. .Bd -literal -offset indent PRINT "Hello world!\en" PRINTLN "Hello world!" PRINT _NARG, " arguments\en" PRINTLN "sum: ", 2+3, " product: ", 2*3 PRINTLN STRFMT("E = %f", 2.718) .Ed .Bl -inset .It Ic PRINT هر یک از آرگومان‌های جدا شده با ویرگول خود را چاپ می‌کند. اعداد به صورت هگزادسیمال بزرگ بدون علامت به همراه یک پیشوند .Sq $ چاپ می‌شوند. برای قالب‌های مختلف، از .Ic STRFMT استفاده کنید. .It Ic PRINTLN هر یک از آرگومان‌های جدا شده با ویرگول خود را، در صورت وجود، به دنبال یک خط جدید .Pq Ql \en چاپ می‌کند. .El .Ss "سقط فرآیند اسمبل (Aborting the assembly process)" دستورات .Ic FAIL و .Ic WARN می‌توانند به ترتیب برای چاپ خطاها و هشدارها در طول فرآیند اسمبل استفاده شوند. این به ویژه برای ماکروهایی که یک آرگومان نامعتبر دریافت می‌کنند مفید است. .Ic FAIL و .Ic WARN یک رشته را به عنوان تنها آرگومان می‌پذیرند و این رشته را به عنوان یک خطای معمولی همراه با شماره خط چاپ می‌کنند. .Pp دستور .Ic FAIL بلافاصله اسمبل کردن را متوقف می‌کند در حالی که .Ic WARN پیام را نمایش می‌دهد اما پس از آن ادامه می‌دهد. .Pp اگر نیاز دارید هنگام کامپایل از صحت فرضیه‌ای اطمینان حاصل کنید، می‌توانید از .Ic ASSERT و .Ic STATIC_ASSERT استفاده کنید. مثال‌های نحوی در زیر آورده شده است: .Bd -literal -offset indent Function: xor a ASSERT LOW(MyByte) == 0 ld h, HIGH(MyByte) ld l, a ld a, [hli] ; You can also indent this! ASSERT BANK(OtherFunction) == BANK(Function) call OtherFunction ; Lowercase also works ld hl, FirstByte ld a, [hli] assert FirstByte + 1 == SecondByte ld b, [hl] ret \&.end ; If you specify one, a message will be printed STATIC_ASSERT .end - Function < 256, "Function is too large!" .Ed .Pp اولاً، تفاوت بین .Ic ASSERT و .Ic STATIC_ASSERT این است که اولی در صورت امکان توسط RGBASM ارزیابی می‌شود، در غیر این صورت توسط RGBLINK؛ اما دومی فقط و فقط توسط RGBASM ارزیابی می‌شود. اگر RGBASM نتواند مقدار آرگومان را برای .Ic STATIC_ASSERT محاسبه کند، خطایی ایجاد می‌کند. .Pp ثانیاً، همانطور که در بالا نشان داده شده است، یک رشته می‌تواند به صورت اختیاری در انتها اضافه شود تا بینشی درباره آنچه که ادعا (assertion) در حال بررسی آن است ارائه دهد. .Pp در نهایت، می‌توانید یکی از گزینه‌های .Ic WARN ، FAIL یا .Ic FATAL را به عنوان اولین آرگومان اختیاری به .Ic ASSERT یا .Ic STATIC_ASSERT اضافه کنید. اگر ادعا شکست بخورد، .Ic WARN باعث صدور یک هشدار ساده (کنترل شده توسط پرچم .Fl Wassert در .Xr rgbasm 1 ) می‌شود؛ .Ic FAIL (حالت پیش‌فرض) باعث یک خطای غیرکشنده می‌شود؛ و .Ic FATAL بلافاصله فرآیند را سقط می‌کند. .Sh "متفرقه (MISCELLANEOUS)" .Ss "تغییر گزینه‌ها هنگام اسمبل (Changing options while assembling)" دستور .Ic OPT می‌تواند برای تغییر برخی از گزینه‌ها در طول اسمبل از درون منبع، به جای تعریف آن‌ها در خط فرمان، استفاده شود. .Pq Xr rgbasm 1 را ببینید . .Pp دستور .Ic OPT فهرستی از گزینه‌ها را که با ویرگول از هم جدا شده‌اند به عنوان آرگومان خود می‌پذیرد: .Bd -literal -offset indent PUSHO OPT g.oOX, Wdiv ; acts like command-line `-g.oOX -Wdiv` OPT -Wdiv ; dashes before the options are optional DW `..ooOOXX ; uses the graphics constant characters from OPT g PRINTLN $80000000/-1 ; prints a warning about division POPO DW `00112233 ; uses the default graphics constant characters PRINTLN $80000000/-1 ; no warning by default .Ed .Pp دستور .Ic OPT می‌تواند گزینه‌های .Cm b ، g ، p ، Q ، r ، و .Cm W را تغییر دهد. .Pp دستورات .Ic POPO و .Ic PUSHO رابط کاربری پشته گزینه‌ها را فراهم می‌کنند. .Ic PUSHO مجموعه فعلی گزینه‌ها را در پشته گزینه‌ها قرار می‌دهد (push می‌کند). سپس بعداً می‌توان از .Ic POPO برای بازیابی آن‌ها استفاده کرد. این قابلیت زمانی مفید است که بخواهید برخی گزینه‌ها را در یک فایل شامل‌شده تغییر دهید و نخواهید گزینه‌های تنظیم‌شده توسط برنامه‌ای که فایل شما را شامل کرده است از بین ببرید. تعداد ورودی‌های پشته تنها با میزان حافظه سیستم شما محدود می‌شود. .Pp دستور .Ic PUSHO همچنین می‌تواند فهرستی از گزینه‌ها را که با ویرگول از هم جدا شده‌اند دریافت کند تا مجموعه فعلی را ذخیره کرده و همزمان مجموعه آرگومان‌ها را اعمال کند: .Bd -literal -offset indent PUSHO b.#, g.oO# DB %..####.. DW `..ooOO## POPO .Ed .Ss "مستثنی کردن مکان‌ها از ردیابی پشته خطا (Excluding locations from backtraces)" خطاها و هشدارها .Em ردیابی پشته (backtraces) را چاپ می‌کنند که مکان رخ دادن مشکل در فایل منبع را نشان می‌دهد، و منشأ مشکل را حتی از طریق زنجیره‌ای از مکان‌های .Ic REPT ، .Ic FOR ، .Ic MACRO ، و .Ic INCLUDE ردیابی می‌کند. گاهی اوقات مکان‌هایی وجود دارند که مایلید نادیده بگیرید؛ به عنوان مثال، یک ماکروی کاربردی رایج هنگامی که فقط به خطی که ماکرو در آن استفاده شده اهمیت می‌دهید، یا یک فایل .Ic INCLUDE که فقط برای شامل کردن سایر فایل‌ها به کار می‌رود و صرفاً پرکننده در ردیابی پشته است. .Pp در این موارد، می‌توانید با یک علامت سؤال .Sq \&? بعد از نشانه (token)، یک مکان را .Em ساکت کنید: تمام مکان‌های ایجاد شده توسط .Sq REPT? ، .Sq FOR? ، یا .Sq MACRO? چاپ نخواهند شد، و هر مکانی که توسط یک .Sq INCLUDE? ، یا فراخوانی ماکرویی که نام آن بلافاصله با یک .Sq \&? دنبال شود، چاپ نخواهد شد. به عنوان مثال، اگر این قطعه کد به صورت .Ql example.asm اسمبل شود: .Bd -literal -offset indent MACRO lb assert -128 <= (\e2) && (\e2) < 256, "\e2 is not a byte" assert -128 <= (\e3) && (\e3) < 256, "\e3 is not a byte" ld \e1, (LOW(\e2) << 8) | LOW(\e3) ENDM SECTION "Code", ROM0 lb hl, $123, $45 .Ed .Pp این یک ردیابی پشته خطا چاپ می‌کند: .Bd -literal -offset indent error: Assertion failed: $123 is not a byte at example.asm::lb(2) <- example.asm(7) .Ed .Pp اما اگر .Ql MACRO به .Ql MACRO? تغییر یابد، یا .Ql lb hl به .Ql lb? hl تغییر یابد، آنگاه ردیابی پشته خطا مکانی درون ماکروی .Ql lb را ذکر نخواهد کرد: .Bd -literal -offset indent error: Assertion failed: $123 is not a byte at example.asm(7) .Ed .Sh "همچنین ببینید (SEE ALSO)" .Xr rgbasm 1 , .Xr rgblink 1 , .Xr rgblink 5 , .Xr rgbfix 1 , .Xr rgbgfx 1 , .Xr gbz80 7 , .Xr rgbasm-old 5 , .Xr rgbds 5 , .Xr rgbds 7 .Sh "تاریخچه (HISTORY)" دستور .Xr rgbasm 1 در ابتدا توسط .An Carsten S\(/orensen به عنوان بخشی از بسته ASMotor نوشته شد و بعداً در RGBDS توسط .An Justin Lloyd دوباره بسته‌بندی شد. اکنون توسط تعدادی از مشارکت‌کنندگان در .Lk https://github.com/gbdev/rgbds نگهداری می‌شود.