RGBASM(5) File Formats Manual RGBASM(5)
rgbasm - مستندات زبان اسمبلی Game Boy

این توضیحات کامل زبان اسمبلی مورد استفاده توسط rgbasm(1) است. برای توضیحات کامل دستورالعمل‌های زبان ماشین پشتیبانی‌شده توسط پردازنده Game Boy، به gbz80(7) مراجعه کنید.

توصیه می‌شود پیش از خواندن این سند، تا حدی با سخت‌افزار Game Boy آشنایی داشته باشید. RGBDS به‌طور ویژه برای Game Boy هدف‌گذاری شده است، بنابراین بسیاری از ویژگی‌های آن مستقیماً با مفاهیم سخت‌افزاری آن گره خورده‌اند. این سند به عنوان مرجع سخت‌افزار Game Boy در نظر گرفته نشده است.

به‌طور کلی، “پیونددهنده” به rgblink(1) اشاره دارد، اما هر برنامه‌ای که فایل‌های شیء RGBDS (توضیح داده شده در rgbds(5)) را پردازش کند، می‌تواند به جای آن استفاده شود.

ساختار دستوری، درست مانند هر اسمبلر دیگری، مبتنی بر خط است. هر خط می‌تواند شامل بخش‌هایی به یکی از این دو ترتیب باشد:

  • [label:] [directive] [; comment]
  • [label:] [instruction [:: instruction ...]] [; comment]

شبه‌دستورها (Directives) فرمان‌هایی به خود اسمبلر هستند، مانند PRINTLN ، SECTION ، یا OPT.

برچسب‌ها یک نام را به مکانی مشخص درون یک بخش پیوند می‌دهند (به Labels در ادامه مراجعه کنید). برچسب‌ها قبل از اکثر شبه‌دستورها مجاز هستند، اما قبل از IF ، ELIF ، ELSE ، ENDC ، REPT ، FOR ، ENDR ، MACRO ، یا ENDM مجاز نیستند.

دستورالعمل‌ها به آپ‌کدهای Game Boy ترجمه (اسمبل) می‌شوند. چندین دستورالعمل در یک خط، و همچنین شبه‌دستورهای داده (به Defining constant data in ROM در ادامه مراجعه کنید)، می‌توانند با دو دونقطه ‘::’ از یکدیگر جدا شوند.

دستورالعمل‌های موجود در gbz80(7) مستند شده‌اند.

توجه داشته باشید در جایی که یک دستورالعمل به یک ثبات ۸ بیتی r8 نیاز دارد، می‌تواند HIGH(r16) را به عنوان ثبات ۸ بیتی بالایی از r16 داده‌شده تفسیر کند؛ برای مثال، HIGH(HL) برای H ؛ و LOW(r16) را به عنوان ثبات پایینی تفسیر کند؛ برای مثال، LOW(HL) برای L (به‌جز برای LOW(AF ،) زیرا F یک ثبات معتبر نیست).

همچنین توجه داشته باشید در جایی که یک دستورالعمل به یک کد وضعیت cc نیاز دارد، می‌تواند !cc را به عنوان کد وضعیت معکوس تفسیر کند؛ برای مثال، !nz برای z.

تمام کلیدواژه‌های رزروشده (شبه‌دستورها، دستورالعمل‌ها، ثبات‌ها، توابع داخلی و غیره) به حروف بزرگ و کوچک حساس نیستند (case-insensitive)؛ تمام شناسه‌ها (برچسب‌ها، متغیرها و غیره) به حروف بزرگ و کوچک حساس هستند (case-sensitive).

توضیحات (Comments) برای ارائه اطلاعاتی درباره کد به انسان‌ها، مانند توضیحات تکمیلی، استفاده می‌شوند. اسمبلر همیشه توضیحات و محتوای آن‌ها را نادیده می‌گیرد.

دو نوع توضیح وجود دارد: درون‌خطی و بلوکی. توضیحات درون‌خطی هر چیزی هستند که پس از یک نقطه‌ویرگول ‘;’ که درون یک رشته نباشد، تا انتهای خط قرار می‌گیرند. توضیحات بلوکی، که با ‘/*’ آغاز شده و با ‘*/’ پایان می‌یابند، می‌توانند در چندین خط پخش شوند یا در میان یک عبارت قرار گیرند.

مثالی که این ویژگی‌های ساختار دستوری را نشان می‌دهد:

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

گاهی اوقات خطوط ممکن است بسیار طولانی شوند و شکستن آن‌ها ضروری باشد. برای این کار، یک بک‌اسلش در انتهای خط قرار دهید:

    DB 1, 2, 3, \
       4, 5, 6, \ ; Put it before any comments
       7, 8, 9
    DB "Hello, \  ; Space before the \ is included
world!"           ; Any leading space is included

نمادهایی با مقادیر رشته‌ای یا عددی می‌توانند با نوشتن آن‌ها درون ‘{braces}’ “درج” شوند (interpolated). این کار محتوای نماد را طوری جای‌گذاری می‌کند که گویی بخشی از فایل منبع بوده‌اند. اگر یک نماد رشته‌ای باشد، نویسه‌های آن به همان صورت درج می‌شوند. اگر یک نماد عددی باشد، مقدار آن به نمادگذاری هگزادسیمال با یک علامت دلار ‘$’ در ابتدا تبدیل می‌شود.

درج نمادها می‌تواند تودرتو نیز باشد.

DEF topic EQUS "life, the universe, and \"everything\""
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}

نمادها را می‌توان حتی در زمینه‌هایی که بسط خودکار ثابت‌های رشته‌ای را غیرفعال می‌کنند درج کرد: یعنی ‘name’ در تمام موارد ‘DEF({name}) ،’ ‘DEF {name} EQU/=/EQUS/etc ... ،’ ‘REDEF {name} EQU/=/EQUS/etc ... ،’ ‘FOR {name}, ... ،’ ‘PURGE {name} ،’ و ‘MACRO {name}’ بسط داده خواهد شد، هرچند در ‘DEF(name) ،’ ‘PURGE {name}’ و غیره بسط داده نخواهد شد.

امکان تغییر نحوه چاپ نمادها با مشخص کردن قالب چاپ به این صورت وجود دارد: ‘{fmt:symbol}’. مشخص‌کننده ‘fmt’ از بخش‌هایی تشکیل شده که باید به ترتیب زیر باشند: ‘<sign><exact><align><pad><width><frac><prec><type>’. تمام این بخش‌ها اختیاری هستند، به‌جز ‘<type>’ که الزامی است. این بخش‌ها عبارتند از:

‘<sign>’ می‌تواند ‘+’ یا ‘باشد.’ در صورت تعیین، این نویسه را در جلوی اعداد غیرمنفی چاپ می‌کند.
‘<exact>’ می‌تواند ‘#’ باشد (تنها برای انواع غیرده‌دهی مجاز است). در صورت تعیین، مقدار را در قالبی «دقیق» چاپ می‌کند: با یک پیشوند مبنا (‘$’ ، ‘&’ ، یا ‘%’) برای انواع صحیح غیرده‌دهی (‘x’ / ‘X’ ، ‘o’ ، یا ‘b’ ؛) با یک پسوند دقت ‘q’ برای اعداد ممیز ثابت؛ یا با نویسه‌های گریز ‘\’ (اما بدون گیومه‌های محصورکننده) برای رشته‌ها.
‘<align>’ می‌تواند ‘-’ باشد. در صورت تعیین، به جای راست، از چپ تراز می‌کند.
‘<pad>’ می‌تواند ‘0’ باشد. در صورت تعیین، اعداد راست‌تراز را به جای فاصله با صفر پر می‌کند.
‘<width>’ می‌تواند یک یا چند نویسه ‘0’ – ‘9’ باشد. در صورت تعیین، مقدار را تا این پهنا پر می‌کند که به‌طور پیش‌فرض با فاصله از راست تراز می‌شود.
‘<frac>’ می‌تواند ‘.’ باشد که با صفر یا چند نویسه ‘0’ – ‘9’ دنبال می‌شود. در صورت تعیین، این تعداد ارقام کسری از یک عدد ممیز ثابت را چاپ می‌کند. به‌طور پیش‌فرض ۵ رقم است و حداکثر ۲۵۵ رقم می‌باشد. (یک ‘.’ که با صفر رقم ‘0’ – ‘9’ دنبال شود، صفر رقم کسری و بدون ممیز اعشاری چاپ می‌کند.)
‘<prec>’ می‌تواند ‘q’ باشد که با یک یا چند نویسه ‘0’ – ‘9’ دنبال می‌شود. در صورت تعیین، یک عدد ممیز ثابت را با این دقت چاپ می‌کند. به‌طور پیش‌فرض روی گزینه جاری -Q تنظیم است.
‘<type>’ نوع مقدار را مشخص می‌کند.

انواع معتبر عبارتند از:

‘d’ ده‌دهی علامت‌دار -42
‘u’ ده‌دهی بدون علامت 4294967254
‘x’ هگزادسیمال با حروف کوچک 2a
‘X’ هگزادسیمال با حروف بزرگ 2A
‘b’ باینری (دودویی) 101010
‘o’ اکتال (هشت‌هشتی) 52
‘f’ ممیز ثابت 1234.56789
‘s’ رشته string contents

مثال‌ها:

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}!"

اگرچه برای این مثال‌ها، STRFMT مناسب‌تر خواهد بود؛ به String expressions در ادامه مراجعه کنید.

دو نوع عبارت وجود دارد: عددی و رشته‌ای.

عبارات عددی همیشه با استفاده از محاسبات ۳۲ بیتی علامت‌دار ارزیابی می‌شوند. در زمینه‌های منطق بولی، صفر تنها عدد «نادرست» (false) در نظر گرفته می‌شود و تمام اعداد غیرصفر (از جمله منفی) «درست» (true) هستند.

یک عبارت «ثابت» نامیده می‌شود اگر مقدار آن را بداند. این عموماً همیشه صادق است، مگر اینکه برچسبی در میان باشد، همان‌طور که در بخش SYMBOLS توضیح داده شده است. با این حال، برخی از عملگرها حتی با عملوندهای غیرثابت نیز می‌توانند ثابت باشند، همان‌طور که در Operators در ادامه توضیح داده شده است.

شبه‌دستورها معمولاً نیازمند عبارات ثابت هستند: برای مثال، REPT نیاز دارد که تعداد تکرارها در زمان ترجمه کد (assembly time) مشخص باشد.

از انواع مختلف لیترال‌های عددی پشتیبانی می‌کند.

Format type
ده‌دهی ندارد 0123456789
هگزادسیمال , 0x, 0X 0123456789ABCDEF
اکتال , 0o, 0O 01234567
باینری , 0b, 0B 01
ممیز ثابت ندارد 01234.56789
ممیز ثابت دقیق ندارد 12.34q8
ثابت نویسه‌ای ندارد 'A'
گرافیک Game Boy ` 0123

خط زیرین (_) نیز در اعداد پذیرفته می‌شود، به‌جز در ابتدای عدد. این می‌تواند برای گروه‌بندی ارقام مفید باشد، مانند ‘123_456’ یا ‘%1100_1001’.

شکل «ثابت نویسه‌ای» مقداری را به دست می‌دهد که نویسه در جدول نگاشت نویسه (charmap) جاری به آن نگاشت شده است. برای مثال، به‌طور پیش‌فرض (به ascii(7) مراجعه کنید) ‘'A'’ مقدار ۶۵ را به دست می‌دهد. یک ثابت نویسه‌ای باید یک مقدار واحد را نشان دهد، بنابراین نمی‌تواند شامل چندین نویسه یا نویسه‌هایی باشد که به چندین مقدار نگاشت می‌شوند. برای اطلاعات درباره نگاشت‌های نویسه به Character maps و برای اطلاعات درباره نویسه‌های گریز مجاز در ثابت‌های نویسه‌ای به String expressions مراجعه کنید.

مورد آخر، گرافیک Game Boy، حداکثر تا هشت رقم بین ۰ و ۳ را انتظار دارد که متناظر با مقادیر سایه دو بیتی پیکسل‌ها هستند. مقدار عددی حاصل، دو بایت داده تایل است که آن سطر از پیکسل‌ها را تولید می‌کند. برای مثال، ‘`01012323’ معادل ‘$0F55’ است.

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

می‌توانید از این عملگرها در عبارات عددی استفاده کنید (فهرست‌شده از بیشترین به کمترین اولویت):

گروه‌بندی
فراخوانی تابع داخلی
به توان رساندن
مثبت یگانی، منفی یگانی (قرینه‌سازی)، متمم (نقیض بیتی)، و نقیض بولی
ضرب، تقسیم (گرد کردن به پایین)، و مدول (باقیمانده)
شیفت‌های بیتی (به چپ، به راست با بسط علامت، به راست با بسط صفر)
& | ^ عملگرهای بیتی AND/OR/XOR
جمع و تفریق
مقایسه‌ها
عملگر بولی AND
عملگر بولی OR

‘**’ عددی را به توان غیرمنفی می‌رساند. این تنها عملگر راست‌تداعی است، به این معنی که ‘p ** q ** r’ برابر است با ‘p ** (q ** r) ،’ نه ‘(p ** q) ** r’. تمام عملگرهای دوگانی دیگر چپ‌تداعی هستند.

‘~’ یک مقدار را با معکوس کردن تمام ۳۲ بیت آن متمم می‌کند.

‘%’ برای دریافت باقیمانده تقسیم متناظر استفاده می‌شود، به‌طوری که ‘x / y * y + x % y == x’ همیشه درست باشد. حاصل دارای همان علامت مقسوم‌علیه است. این باعث می‌شود ‘x % y’ برابر با ‘(x + y) % y’ یا ‘(x - y) % y’ باشد.

شیفت دادن با جابجایی تمام بیت‌ها در عملوند سمت چپ به چپ (‘<<’) یا به راست (‘>>’) به میزان مقدار عملوند سمت راست انجام می‌شود. هنگام شیفت به چپ، تمام بیت‌های تازه درج‌شده صفر می‌شوند؛ هنگام شیفت به راست، به جای آن کپی‌هایی از باارزش‌ترین بیت اصلی هستند. این امر ‘a << b’ و ‘a >> b’ را به ترتیب معادل ضرب و تقسیم بر ۲ به توان b می‌کند.

عملگرهای مقایسه اگر مقایسه نادرست باشد ۰، و در غیر این صورت ۱ را برمی‌گردانند.

برخلاف بسیاری از زبان‌های دیگر، و به دلایل فنی، همچنان هر دو عملوند ‘&&’ و ‘||’ را ارزیابی می‌کند.

عملگرهای ‘&&’ و ‘&’ با یک ثابت صفر به عنوان هر یک از عملوندها، مقدار ثابت ۰ خواهند بود، و ‘||’ با یک ثابت غیرصفر به عنوان هر یک از عملوندها، مقدار ثابت ۱ خواهد بود، حتی اگر عملوند دیگر غیرثابت باشد.

‘!’ اگر عملوند ۰ باشد ۱ را برمی‌گرداند، و در غیر این صورت ۰ را برمی‌گرداند. حتی یک عملوند غیرثابت با هر بیت غیرصفر مقدار ۰ را برمی‌گرداند.

علاوه بر عملگرها، توابعی نیز وجود دارند که کاربردهای تخصصی‌تری دارند:

(n) معادل با ‘(n & $FF00) >> 8’.
(n) معادل با ‘n & $FF’.
(n) تعداد بیت‌های لازم برای نمایش n را برمی‌گرداند. برخی فرمول‌های مفید: BITWIDTH(n) - 1 برابر با ⌊log2(n)⌋ است؛ BITWIDTH(n - 1) برابر با ⌈log2(n)⌉ است؛ و 32 - BITWIDTH(n) برابر با clz(n) ، یعنی تعداد بیت‌های صفر آغازین در نمایش باینری n است.
(n) مقدار ctz(n) ، یعنی تعداد بیت‌های صفر پایانی در نمایش باینری n را برمی‌گرداند.

اعداد ممیز ثابت از نظر فنی همان اعداد صحیح هستند، اما از نظر مفهومی دارای ممیز اعشاری در مکانی ثابت هستند (به همین دلیل این نام را دارند). این امر به آن‌ها دقت بیشتری می‌دهد، به بهای دامنه کوچک‌تر، در حالی که دستکاری آن‌ها بسیار کم‌هزینه‌تر از اعداد ممیز شناور باقی می‌ماند (که از آن‌ها پشتیبانی نمی‌کند).

دقت پیش‌فرض تمام اعداد ممیز ثابت ۱۶ بیت است، به این معنی که ۱۶ بیت پایینی برای بخش کسری استفاده می‌شوند؛ بنابراین آن‌ها در واحدهای یک شصت‌وپنج‌هزاروپانصدوسی‌وششم (65536ths) از ۱.۰ شمارش می‌شوند. این دقت را می‌توان با گزینه خط فرمان -Q و/یا با OPT Q تغییر داد (به Changing options while assembling مراجعه کنید). یک لیترال ممیز ثابت مجزا می‌تواند دقت خود را مشخص کند و پیش‌فرض جاری را لغو نماید، با افزودن یک “q” که پس از آن تعداد بیت‌های کسری می‌آید: برای مثال، ‘789.25q8’ برابر با $000315_40 ( =789.25*28 ) است.

از آنجا که مقادیر ممیز ثابت همچنان همان اعداد صحیح هستند، می‌توانید از آن‌ها در عبارات عادی اعداد صحیح استفاده کنید. به‌راحتی می‌توانید یک عدد ممیز ثابت را با شیفت دادن آن به راست به تعداد بیت‌های کسری، یا با تقسیم آن بر ۱.۰، به یک عدد صحیح برش دهید (truncate). نتیجه می‌شود که می‌توانید یک عدد صحیح را با شیفت دادن آن به چپ به همان میزان، یا با ضرب کردن آن در ۱.۰، به یک عدد ممیز ثابت تبدیل کنید. برای مثال، ‘123.0 / 1.0 == 123 ،’ و ‘123 * 1.0 == 123.0’.

توجه داشته باشید که تعداد بیت‌های کسری جاری را می‌توان به صورت TZCOUNT(1.0) محاسبه کرد.

توابع زیر برای کار با اعداد ممیز ثابت طراحی شده‌اند (که باید ثابتِ مشخص باشند):

(x, y) تقسیم ممیز ثابت
(x, y) ضرب ممیز ثابت
(x, y) مدول ممیز ثابت
(x, y) xy
(x, y) لگاریتم x در مبنای y
(x) گرد کردن x به نزدیک‌ترین عدد صحیح (نیمه به دور از صفر)
(x) گرد کردن x به بالا به نزدیک‌ترین عدد صحیح
(x) گرد کردن x به پایین به نزدیک‌ترین عدد صحیح
(x) سینوس x
(x) کسینوس x
(x) تانژانت x
(x) وارون سینوس x
(x) وارون کسینوس x
(x) وارون تانژانت x
(y, x) زاویه بین (x,y) و (1,0)

هیچ تابعی برای جمع و تفریق ممیز ثابت وجود ندارد، زیرا عملگرهای ‘+’ و ‘-’ می‌توانند جفت عملوندهای ممیز ثابت را با هم جمع و تفریق کنند.

توجه داشته باشید که برخی عملگرها یا توابع هنگام ترکیب اعداد صحیح و مقادیر ممیز ثابت معنادار هستند. برای مثال، ‘2.0 * 3’ معادل با ‘MUL(2.0, 3.0)’ است، و ‘6.0 / 2’ معادل با ‘DIV(6.0, 2.0)’ است. هنگام انجام این نوع کارها مراقب باشید و در مورد معنای عملیات‌ها فکر کنید.

همه این توابع ممیز ثابت می‌توانند یک آرگومان نهایی اختیاری بگیرند که دقتی است که باید برای همان یک عملیات استفاده شود. برای مثال، ‘MUL(6.0q8, 7.0q8, 8)’ صرف‌نظر از اینکه چه مقداری به عنوان گزینه جاری Q تنظیم شده باشد، به ‘42.0q8’ ارزیابی می‌شود. سازگاری دقت‌ها را بررسی نمی‌کند ، بنابراین ورودی بی‌معنی مانند ‘MUL(4.2q8, 6.9q12, 16)’ نتیجه‌ای بی‌معنی (اما از نظر فنی صحیح) تولید خواهد کرد: “خروجی بی‌ارزش حاصل ورودی بی‌ارزش است (garbage in, garbage out)”.

تابع FMOD برای به دست آوردن باقیمانده تقسیم ممیز ثابت متناظر استفاده می‌شود. نتیجه دارای همان علامت مقسوم است؛ این برعکس نحوه کار عملگر مدول اعداد صحیح ‘%’ است!

توابع مثلثاتی (SIN ، COS ، TAN ، و غیره) بر حسب دایره‌ای تقسیم‌شده به ۱.۰ “دور (turn)” (برابر با 2π رادیان، یا ۳۶۰ درجه) تعریف شده‌اند.

این توابع برای تولید خودکار جداول مختلف مفید هستند. برای مثال:

; 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

ابتدایی‌ترین عبارت رشته‌ای، یک لیترال رشته‌ای است: هر تعداد نویسه که درون گیومه دوتایی قرار گرفته باشند (‘"for instance"’). نویسه بک‌اسلش ‘\’ خاص است از این جهت که باعث می‌شود نویسه بعد از آن “گریز داده شود (escaped) ،” به این معنی که به گونه‌ای متفاوت از حالت معمول با آن رفتار می‌شود. تعدادی توالی گریز وجود دارد که می‌توانید درون یک رشته استفاده کنید:

‘\\’ بک‌اسلش (خود نویسه گریز را گریز می‌دهد)
‘\"’ گیومه دوتایی (به رشته پایان نمی‌دهد)
‘\'’ گیومه تکی (به لیترال نویسه‌ای پایان نمی‌دهد)
‘\{’ آکولاد باز (درج نماد را آغاز نمی‌کند)
‘\}’ آکولاد بسته (به درج نماد پایان نمی‌دهد)
‘\n’ خط جدید (ASCII $0A)
‘\r’ بازگشت به ابتدای سطر (Carriage return) (ASCII $0D)
‘\t’ تب (ASCII $09)
‘\0’ نال (ASCII $00)

لیترال‌های رشته‌ای چندخطی در گیومه‌های سه‌تایی قرار می‌گیرند (‘"""for instance"""’). توالی‌های گریز در رشته‌های چندخطی به همان صورت کار می‌کنند؛ با این حال، نویسه‌های خط جدید تحت‌اللفظی به همان شکل گنجانده می‌شوند، بدون نیاز به گریز دادن آن‌ها با ‘\r’ یا ‘\n’.

لیترال‌های رشته‌ای خام با یک علامت هش ‘#’ پیشوندگذاری می‌شوند. درون آن‌ها، بک‌اسلش‌ها و آکولادها مانند نویسه‌های معمولی تلقی می‌شوند، بنابراین به عنوان آرگومان‌های ماکرو، نمادهای درج‌شده یا توالی‌های گریز بسط داده نخواهند شد. برای مثال، رشته خام ‘#"\t\1{s}\"’ معادل با رشته معمولی ‘"\\t\\1\{s}\\"’ است. (توجه داشته باشید که این امر مانع از گنجاندن نویسه گیومه دوتایی در رشته‌های خام می‌شود.) رشته‌های خام نیز ممکن است درون گیومه‌های سه‌تایی قرار گیرند تا چندخطی باشند، بنابراین می‌توانند شامل نویسه‌های خط جدید یا گیومه تحت‌اللفظی باشند (هرچند همچنان سه گیومه متوالی مجاز نیست).

می‌توانید از عملگر ‘++’ برای الحاق دو رشته استفاده کنید. ‘"str" ++ "ing"’ معادل با ‘"string" ،’ یا معادل با ‘STRCAT("str", "ing")’ است.

می‌توانید از عملگرهای ‘===’ و ‘!==’ برای مقایسه دو رشته استفاده کنید. ‘"str" === "ing"’ معادل با ‘STRCMP("str", "ing") == 0 ،’ و ‘"str" !== "ing"’ معادل با ‘STRCMP("str", "ing") != 0’ است.

توابع زیر روی عبارات رشته‌ای عمل می‌کنند و خودشان رشته برمی‌گردانند:

(strs...) رشته‌های strs را الحاق می‌کند.
(str) رشته str را با تمام حروف اسکی (‘a-z’) به صورت حروف بزرگ برمی‌گرداند.
(str) رشته str را با تمام حروف اسکی (‘A-Z’) به صورت حروف کوچک برمی‌گرداند.
(str, start, stop) یک زیررشته از str را که از start آغاز شده و به stop ختم می‌شود (غیرشامل) برمی‌گرداند. اگر stop مشخص نشده باشد، زیررشته تا انتهای str ادامه می‌یابد.
(str, old, new) رشته str را با جایگزینی هر رخداد زیررشته old با new برمی‌گرداند.
(fmt, args...) رشته fmt را بازمی‌گرداند در حالی که هر الگوی ‘%spec’ با درج قالب spec (با استفاده از همان ساختار دستوری Symbol interpolation) با آرگومان متناظر آن در args جایگزین شده است (‘%%’ با نویسه ‘%’ جایگزین می‌شود).
(str, idx) زیررشته‌ای از str را برای ورودی جدول نگاشت نویسه در اندیس idx با نگاشت نویسه جاری برمی‌گرداند. (idx ورودی‌های نگاشت نویسه را می‌شمارد، نه نویسه‌ها را.)

توابع زیر عملوندهای مختلفی می‌گیرند و رشته برمی‌گردانند:

(vals...) رشته‌ای را که با نگاشت نویسه جاری به vals نگاشت شده برمی‌گرداند. اگر ورودی نگاشت نویسه یکتایی برای vals وجود نداشته باشد، خطا رخ می‌دهد.
(name, max) محتوای فایل name را به صورت رشته برمی‌گرداند. حداکثر تا max بایت را می‌خواند، یا اگر max مشخص نشده باشد، کل محتوا را می‌خواند. اگر فایل در دایرکتوری جاری یافت نشود، فهرست مسیرهای include ارائه‌شده به گزینه -I -دستور rgbasm(1) در خط فرمان جستجو خواهد شد.

توابع زیر روی عبارات رشته‌ای عمل می‌کنند، اما اعداد صحیح برمی‌گردانند:

(str) تعداد نویسه‌ها در str را برمی‌گرداند.
(str1, str2) رشته‌های str1 و str2 را بر اساس ترتیب اسکی نویسه‌هایشان مقایسه می‌کند. اگر str1 کمتر از str2 باشد -1، اگر str1 بزرگتر از str2 باشد 1، و اگر با هم مطابقت داشته باشند 0 برمی‌گرداند.
(str, sub) اولین اندیس رخداد sub در str را برمی‌گرداند، یا اگر موجود نباشد -1 برمی‌گرداند.
(str, sub) آخرین اندیس رخداد sub در str را برمی‌گرداند، یا اگر موجود نباشد -1 برمی‌گرداند.
(str) تعداد بایت‌ها در str را برمی‌گرداند. (نویسه‌های غیراسکی می‌توانند چندین بایت باشند.)
(str, idx) مقدار بایت را در اندیس idx در str برمی‌گرداند.
(str) اگر str ورودی‌ای در نگاشت نویسه جاری داشته باشد 1، و در غیر این صورت 0 برمی‌گرداند.
(str) تعداد ورودی‌های نگاشت نویسه در str را با نگاشت نویسه جاری برمی‌گرداند.
(str1, str2) رشته‌های str1 و str2 را بر اساس مقادیر ورودی‌های نگاشت نویسه آن‌ها با نگاشت نویسه جاری مقایسه می‌کند. اگر str1 کمتر از str2 باشد -1، اگر str1 بزرگتر از str2 باشد 1، و اگر با هم مطابقت داشته باشند 0 برمی‌گرداند.
(char) تعداد مقادیر موجود در ورودی نگاشت نویسه برای char را با نگاشت نویسه جاری برمی‌گرداند.
(char, idx) مقدار موجود در اندیس idx از ورودی نگاشت نویسه برای char را برمی‌گرداند. اگر idx مشخص نشده باشد، char باید دارای یک مقدار واحد باشد که همان برگردانده می‌شود.

توجه داشته باشید که اندیس‌ها از ابتدا با ۰، یا از انتها با ۱- شمارش می‌شوند. نویسه‌های یک رشته توسط ‘STRLEN ؛’ ورودی‌های نگاشت نویسه یک رشته توسط ‘CHARLEN ؛’ و مقادیر یک ورودی نگاشت نویسه توسط ‘CHARSIZE’ شمارش می‌شوند.

هنگام نوشتن رشته‌های متنی که قرار است روی Game Boy نمایش داده شوند، ممکن است رمزگذاری نویسه در ROM با رمزگذاری فایل منبع تفاوت داشته باشد. برای مثال، تایل‌های مورد استفاده برای حروف بزرگ ممکن است با شروع از اندیس تایل ۱۲۸ قرار گیرند، که با اسکی که از ۶۵ آغاز می‌شود متفاوت است.

نگاشت‌های نویسه امکان نگاشت رشته‌ها یا لیترال‌های نویسه‌ای را به توالی‌های دلخواهی از اعداد فراهم می‌کنند:

CHARMAP "A", 42
CHARMAP ':)', 39
CHARMAP "<br>", 13, 10
CHARMAP '&euro;', $20ac

این منجر به این می‌شود که ‘db "Amen :)<br>"’ معادل با ‘db 42, 109, 101, 110, 32, 39, 13, 10 ،’ و ‘dw "25&euro;"’ معادل با ‘dw 50, 53, $20ac’ باشد.

نگاشت‌های نویسه به صورت حریصانه (greedily) تطبیق داده می‌شوند، بنابراین طولانی‌ترین نگاشت قابل اعمال در یک رشته نگاشت خواهد شد. هر نویسه‌ای در رشته که بدون نگاشت تعریف‌شده باشد، مستقیماً و با استفاده از رمزگذاری نویسه‌ها به بایت‌های فایل منبع کپی خواهد شد.

امکان ایجاد چندین نگاشت نویسه و سپس جابجایی بین آن‌ها بر حسب نیاز وجود دارد. برای مثال، می‌توان از این ویژگی برای رمزگذاری اطلاعات اشکال‌زدایی در اسکی و استفاده از رمزگذاری متفاوت برای اهداف دیگر استفاده کرد. در ابتدا، یک نگاشت نویسه به نام ‘main’ وجود دارد و از آغاز به‌طور خودکار به عنوان نگاشت نویسه جاری انتخاب می‌شود. همچنین یک پشته نگاشت نویسه وجود دارد که می‌توان از آن برای ذخیره و بازیابی نگاشت نویسه فعال جاری استفاده کرد.

name یک نگاشت نویسه جدید و خالی به نام name ایجاد کرده و به آن سوئیچ می‌کند.
name, basename یک نگاشت نویسه جدید به نام name ایجاد می‌کند که از نگاشت نویسه basename کپی شده است، و به آن سوئیچ می‌کند.
name به نگاشت نویسه name سوئیچ می‌کند.
نگاشت نویسه جاری را روی پشته قرار می‌دهد (push).
name نگاشت نویسه جاری را روی پشته قرار داده و به نگاشت نویسه name سوئیچ می‌کند.
یک نگاشت نویسه را از پشته برمی‌دارد (pop) و به آن سوئیچ می‌کند.

نکته: تغییرات اعمال‌شده روی یک نگاشت نویسه بلافاصله از همان نقطه به بعد اثرگذار خواهند بود.

چند تابع دیگر وجود دارند که کارهایی فراتر از عملیات عددی یا رشته‌ای انجام می‌دهند:

(symbol) اگر symbol تعریف شده باشد ۱، و در غیر این صورت ۰ برمی‌گرداند. ثابت‌های رشته‌ای درون پرانتزها بسط داده نمی‌شوند.
(arg) اگر مقدار arg توسط RGBASM شناخته‌شده باشد ۱ (مثلاً اگر بتواند آرگومانی برای IF باشد)، یا اگر فقط RGBLINK بتواند مقدار آن را محاسبه کند ۰ برمی‌گرداند.
BANK(arg) یک شماره بانک را برمی‌گرداند. اگر arg نماد @ باشد، این تابع بانکِ بخش جاری را برمی‌گرداند. اگر arg یک رشته باشد، بانک بخشی را که دارای آن نام است برمی‌گرداند. اگر arg یک برچسب باشد، شماره بانکی را که برچسب در آن قرار دارد برمی‌گرداند. اگر قادر به محاسبه آن باشد، حاصل ممکن است ثابت باشد.
(symbol) نام بخشی را که symbol در آن تعریف شده است برمی‌گرداند. symbol باید پیش‌تر تعریف شده باشد. اگر arg نماد @ باشد، این تابع نام بخش جاری را برمی‌گرداند.
(arg) اگر arg یک رشته باشد، این تابع اندازه بخش با نام arg را برمی‌گرداند. اگر arg یک کلیدواژه نوع بخش باشد، اندازه آن نوع بخش را برمی‌گرداند. حاصل ثابت نیست، زیرا تنها RGBLINK می‌تواند مقدار آن را محاسبه کند. اگر arg یک ثبات ۸ بیتی یا ۱۶ بیتی باشد، اندازه آن ثبات را برمی‌گرداند.
(arg) اگر arg یک رشته باشد، این تابع آدرس شروع بخش با نام arg را برمی‌گرداند. اگر arg یک کلیدواژه نوع بخش باشد، آدرس شروع آن نوع بخش را برمی‌گرداند. حاصل ثابت نیست، زیرا تنها RGBLINK می‌تواند مقدار آن را محاسبه کند.

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

SECTION name, type
SECTION name, type, options
SECTION name, type[addr]
SECTION name, type[addr], options

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

انواع type ممکن برای بخش به شرح زیر هستند:

یک بخش ROM. addr می‌تواند از $0000 تا $3FFF ، یا از $0000 تا $7FFF در صورت فعال بودن حالت tiny ROM در پیونددهنده باشد.
یک بخش ROM بانک‌بندی‌شده (banked). addr می‌تواند از $4000 تا $7FFF باشد. در صورت فعال بودن حالت tiny ROM در پیونددهنده، به نام مستعاری برای ROM0 تبدیل می‌شود.
یک بخش رم ویدیویی (VRAM) بانک‌بندی‌شده. addr می‌تواند از $8000 تا $9FFF باشد. bank می‌تواند ۰ یا ۱ باشد، اما اگر حالت DMG در پیونددهنده فعال باشد، بانک ۱ در دسترس نیست.
یک بخش رم خارجی (ذخیره‌سازی) بانک‌بندی‌شده. addr می‌تواند از $A000 تا $BFFF باشد.
یک بخش رم عمومی (general-purpose RAM). addr می‌تواند از $C000 تا $CFFF ، یا از $C000 تا $DFFF در صورت فعال بودن حالت WRAM0 در پیونددهنده باشد.
یک بخش رم عمومی بانک‌بندی‌شده. addr می‌تواند از $D000 تا $DFFF باشد. bank می‌تواند از ۱ تا ۷ باشد. در صورت فعال بودن حالت WRAM0 در پیونددهنده، به نام مستعاری برای WRAM0 تبدیل می‌شود.
یک بخش رم ویژگی اشیاء (OAM). addr می‌تواند از $FE00 تا $FE9F باشد.
یک بخش رم بالا (High RAM). addr می‌تواند از $FF80 تا $FFFE باشد.

مجموعه RGBDS رام‌ها (ROMs) را تولید می‌کند، به این معنی که کد و داده فقط می‌توانند در بخش‌های ROM0 و ROMX قرار گیرند. سایر انواع بخش‌های RAM برای برچسب‌هایی با تخصیص ایستا هستند. اگر به کد یا داده در RAM نیاز دارید، باید خودتان آن را از ROM به RAM کپی کنید. برای نمونه‌ای از چگونگی انجام راحت این کار با یک بلوک LOAD ، به RAM code مراجعه کنید.

گزینه‌های option با کاما جدا می‌شوند و ممکن است شامل موارد زیر باشند:

[bank]
مشخص می‌کند که پیونددهنده بخش را در کدام bank قرار دهد. برای مقادیر ممکن bank بسته به type ، به بالا مراجعه کنید.
[align, offset]
بخش را در آدرسی قرار می‌دهد که align بیت کم‌ارزش آن برابر با offset باشند. توجه داشته باشید که ALIGN[align] کوتاه‌نوشتی برای ALIGN[align, 0] است. این گزینه می‌تواند همراه با [addr] استفاده شود، تا زمانی که با یکدیگر تناقض نداشته باشند. همچنین می‌توان در میانه یک بخش تراز درخواست کرد؛ به Requesting alignment در ادامه مراجعه کنید.

اگر [addr] مشخص نشده باشد، بخش “شناور (floating)” در نظر گرفته می‌شود؛ پیونددهنده به‌طور خودکار آدرس مناسبی را برای بخش محاسبه خواهد کرد. به همین ترتیب، اگر BANK[bank] مشخص نشده باشد، پیونددهنده به‌طور خودکار بانکی با فضای کافی پیدا خواهد کرد.

بخش‌ها را می‌توان با استفاده از یک فایل اسکریپت پیونددهنده نیز مکان‌یابی کرد. قالب آن در rgblink(5) توضیح داده شده است. این اسکریپت‌ها به کاربر اجازه می‌دهند بخش‌های شناور را در بانک مورد نظر و به ترتیبی که در اسکریپت مشخص شده قرار دهد. این امر زمانی مفید است که نتوان بخش‌ها را به‌صورت دستی در یک آدرس قرار داد زیرا اندازه ممکن است تغییر کند، اما بخش‌ها باید در کنار هم باشند.

مثال‌های بخش:

  • SECTION "Cool Stuff", ROMX

    این دستور به بخش با نام “Cool Stuff” سوئیچ می‌کند و اگر از قبل وجود نداشته باشد، آن را ایجاد می‌نماید. این بخش می‌تواند در هر بانک ROM قرار گیرد. کد و داده می‌توانند پس از آن بیایند.

  • در صورت نیاز، می‌توان آدرس پایه بخش را مشخص کرد:
    SECTION "Cool Stuff", ROMX[$4567]
  • مثالی با بانک ثابت:
    SECTION "Cool Stuff", ROMX[$4567], BANK[3]
  • و اگر بخواهید تنها بانک بخش را اجبار کنید و نه موقعیت آن در بانک را، این نیز ممکن است:
    SECTION "Cool Stuff", ROMX, BANK[7]
  • مثال‌های ترازسازی: مورد اول می‌تواند برای تعریف یک بافر OAM که قرار است با DMA منتقل شود مفید باشد، زیرا باید در مرز ۲۵۶ بایت تراز شود. مورد دوم نیز می‌تواند برای GBC HDMA، یا برای یک کد کپی بهینه‌شده که نیازمند ترازسازی است مناسب باشد.
    SECTION "OAM Data", WRAM0, ALIGN[8] ; align to 256 bytes
    SECTION "VRAM Data", ROMX, BANK[2], ALIGN[4] ; align to 16 bytes

بخش جاری را می‌توان بدون شروع یک بخش جدید با استفاده از ENDSECTION پایان داد. این شبه‌دستور زمینه بخش را پاک می‌کند، بنابراین تا زمانی که بخش دیگری را شروع نکنید دیگر نمی‌توانید کد بنویسید. این می‌تواند برای جلوگیری از تعریف تصادفی کد یا داده در بخش اشتباه مفید باشد.

POPS و PUSHS رابط کار با پشته بخش را فراهم می‌کنند. تعداد ورودی‌ها در پشته تنها به میزان حافظه موجود در سیستم شما محدود می‌شود.

PUSHS زمینه بخش جاری را روی پشته بخش قرار می‌دهد (push). سپس می‌توان از POPS بعداً برای بازیابی آن استفاده کرد. این ویژگی برای تعریف بخش‌ها در فایل‌های include مفید است وقتی نمی‌خواهید زمینه بخش در نقطه‌ای که فایل include شده بازنویسی شود.

PUSHS همچنین می‌تواند همان آرگومان‌های SECTION را بگیرد تا زمینه بخش جاری را در پشته قرار داده و همزمان یک بخش جدید تعریف کند:

SECTION "Code", ROM0
Function:
    ld a, 42
    PUSHS "Variables", WRAM0
        wAnswer: db
    POPS
    ld [wAnswer], a

گاهی اوقات می‌خواهید کدی (یا داده‌ای) در RAM داشته باشید، مثلاً برای کد خودتغییردهنده (self-modifying code). اما نمی‌توانید آن را مستقیماً در یک بخش RAM قرار دهید؛ بلکه باید آن را در ROM ذخیره کرده و در نقطه‌ای از زمان به RAM کپی کنید. این بدان معنی است که کد در محدوده آدرسی متفاوت از جایی که تعریف شده اجرا خواهد شد، که این می‌تواند برای ارجاع به برچسب‌های درون آن کد ناخوشایند باشد. این وضعیت دقیقاً همان چیزی است که بلوک‌های LOAD برای آن طراحی شده‌اند. در اینجا مثالی از نحوه استفاده از آن‌ها آمده است:

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!\0"
  ENDL
.end

یک بلوک LOAD شبیه به اعلان SECTION به نظر می‌رسد زیرا یک بخش جدید ایجاد می‌کند. تمام داده‌ها و کدهای تولیدشده در چنین بلوکی مانند معمول در بخش جاری قرار می‌گیرند، اما تمام برچسب‌ها طوری ایجاد می‌شوند که گویی در این بخش تازه‌تأسیس قرار گرفته‌اند.

در مثال بالا، تمام کدها و داده‌ها در بخش “LOAD example” قرار خواهند گرفت. متوجه برچسب‌های ‘RAMCode’ و ‘RAMLocation’ خواهید شد. اولی در ROM واقع شده است، جایی که کد ذخیره می‌شود؛ دومی در RAM قرار دارد، جایی که کد بارگذاری خواهد شد.

نمی‌توانید بلوک‌های LOAD را تودرتو کنید، و همچنین نمی‌توانید بخش جاری را در درون آن‌ها تغییر دهید یا متوقف سازید.

بلوک LOAD جاری را می‌توان با استفاده از ENDL پایان داد. این شبه‌دستور تنها زمانی لازم است که بخواهید نوشتن کد را در بخش ROM دربرگیرنده آن از سر بگیرید. هر یک از دستورهای LOAD ، SECTION ، ENDSECTION ، یا POPS پیش از انجام عملکرد خود، بلوک LOAD جاری را پایان خواهند داد.

بلوک‌های LOAD می‌توانند از اصلاح‌کننده‌های UNION یا FRAGMENT همان‌طور که در بخش Unionized sections در ادامه شرح داده شده استفاده کنند.

هنگامی که با کمبود RAM مواجه هستید، ممکن است بخواهید تخصیص‌های حافظه ایستای همپوشان تعریف کنید، همان‌طور که در بخش Allocating overlapping spaces in RAM توضیح داده شده است. با این حال، یک UNION تنها درون یک فایل منفرد کار می‌کند، بنابراین نمی‌تواند مثلاً برای تعریف متغیرهای موقت در چندین فایل استفاده شود که همگی از یک حافظه تخصیص‌یافته ایستای مشترک استفاده می‌کنند. بخش‌های مشترک (Unionized sections) این مشکل را برطرف می‌کنند. برای اعلان یک بخش مشترک، کلیدواژه UNION را بعد از کلیدواژه SECTION اضافه کنید؛ اعلان در سایر موارد تفاوتی ندارد. بخش‌های مشترک از چند قانون متفاوت نسبت به بخش‌های معمولی پیروی می‌کنند:

  • همان بخش مشترک (یعنی دارای نام یکسان) را می‌توان چندین بار در هر فراخوانی و در چندین فراخوانی اعلام کرد. با اعلان‌های مختلف به صورت یکسان رفتار شده و ادغام می‌شوند، چه در یک فراخوانی باشند یا فراخوانی‌های متفاوت.
  • اگر یک بخش به عنوان مشترک اعلان شده باشد، تمام بخش‌های با همان نام نیز باید به صورت مشترک اعلان شوند.
  • تمام اعلان‌ها باید نوع یکسانی داشته باشند. برای مثال، حتی اگر فلگ -w دستور rgblink(1) استفاده شده باشد، انواع WRAM0 و WRAMX همچنان متفاوت در نظر گرفته می‌شوند.
  • می‌توان قیدهای متفاوتی (ترازسازی، بانک و غیره) برای هر اعلان بخش مشترک تعیین کرد، اما همه آن‌ها باید سازگار باشند. برای مثال، ترازسازی باید با هر آدرس ثابتی سازگار باشد، تمام بانک‌های مشخص‌شده باید یکسان باشند، و غیره.
  • بخش‌های مشترک نمی‌توانند دارای نوع ROM0 یا ROMX باشند.

اعلان‌های مختلف از یک بخش مشترک یکسان به یکدیگر ضمیمه نمی‌شوند، بلکه درست مانند Allocating overlapping spaces in RAM بر روی یکدیگر منطبق و همپوشان می‌شوند. به همین ترتیب، اندازه یک بخش مشترک برابر با بزرگ‌ترین اندازه در میان تمام اعلان‌های آن است.

قطعات بخش (Section fragments)، بخش‌هایی با یک تغییر کوچک هستند: هنگامی که چندین قطعه با یک نام یافت می‌شوند، به جای ایجاد خطا، در قالب یک بخش به هم الحاق می‌شوند، حتی در چندین فایل شیء. این امر درون یک فایل کار می‌کند (همانند رفتاری که بخش‌های «ساده» در نسخه‌های قبلی داشتند)، اما در میان فایل‌های شیء مختلف نیز کار می‌کند. برای اعلان یک قطعه بخش، کلیدواژه FRAGMENT را بعد از کلیدواژه SECTION اضافه کنید؛ اعلان در سایر موارد تفاوتی ندارد. با این حال، مشابه با Unionized sections ، باید برخی قوانین رعایت شوند:

  • اگر یک بخش به عنوان قطعه اعلان شده باشد، تمام بخش‌های با همان نام نیز باید به صورت قطعه اعلان شوند.
  • تمام اعلان‌ها باید دارای نوع یکسانی باشند. برای مثال، حتی اگر فلگ -w دستور rgblink(1) استفاده شده باشد، انواع WRAM0 و WRAMX همچنان متفاوت در نظر گرفته می‌شوند.
  • می‌توان قیدهای متفاوتی (ترازسازی، بانک و غیره) برای هر اعلان قطعه بخش تعیین کرد، اما همه آن‌ها باید سازگار باشند. برای مثال، ترازسازی باید با هر آدرس ثابتی سازگار باشد، تمام بانک‌های مشخص‌شده باید یکسان باشند، و غیره.
  • یک قطعه بخش نمی‌تواند مشترک (unionized) باشد؛ زیرا در نهایت، چنین چیزی چندان منطقی نخواهد بود.

هنگامی که RGBASM دو قطعه را ادغام می‌کند، قطعه‌ای که دیرتر یافت شده به قطعه‌ای که زودتر یافت شده ضمیمه می‌شود.

هنگامی که RGBLINK دو قطعه را ادغام می‌کند، قطعه‌ای که فایل آن در انتها مشخص شده، به قطعه‌ای که فایل آن در ابتدا مشخص شده ضمیمه می‌شود. برای مثال، با فرض اینکه ‘bar.o ،’ ‘baz.o ،’ و ‘foo.o’ همگی حاوی قطعه‌ای با همان نام باشند، دستور

rgblink -o rom.gb baz.o foo.o bar.o
ابتدا قطعه حاصل از ‘baz.o ،’ سپس قطعه حاصل از ‘foo.o ،’ و در پایان قطعه حاصل از ‘bar.o’ را تولید خواهد کرد.

لیترال‌های قطعه (Fragment literals) برای بلوک‌های کوتاهی از کد یا داده که تنها یک بار به آن‌ها ارجاع داده می‌شود مفید هستند. آن‌ها قطعات بخشی هستند که با محصور کردن دستورالعمل‌ها یا شبه‌دستورها با براکت‌های دوتایی ‘[[’ و ‘]]’ ایجاد می‌شوند، بدون نیاز به اعلان جداگانه SECTION FRAGMENT.

محتوای یک لیترال قطعه تبدیل به یک SECTION FRAGMENT می‌شود، که نام و بانک یکسانی با بخش ROM والد خود به اشتراک می‌گذارد، اما بدون هیچ قید دیگری. همچنین بخش والد اگر از قبل یک قطعه نبوده باشد، به یک FRAGMENT تبدیل می‌شود، تا بتواند با لیترال‌های قطعه خود ادغام گردد. پیونددهنده RGBLINK قطعات را بدون ترتیب خاصی ادغام می‌کند.

یک لیترال قطعه می‌تواند جایگزین هر ثابت عدد صحیح ۱۶ بیتی ‘n16’ از مستندات gbz80(7) و همچنین یک مورد DW شود. سپس لیترال قطعه به آدرس شروع خود ارزیابی می‌شود. برای مثال، می‌توانید به یک لیترال قطعه CALL یا JP بزنید.

این کد با استفاده از برچسب‌های نام‌گذاری‌شده:

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\0"
Right: db "right\0"

معادل با این کد با استفاده از لیترال‌های قطعه است:

DataTable:
    dw [[ db 1 ]]
    dw [[ db 4 ]]
    dw [[ db 9 ]]
Routine:
    push hl
    ld hl, [[ db "left\0" ]]
    jr z, .got_it
    ld hl, [[ db "right\0" ]]
.got_it
    call [[
        ld de, $1003
        ld bc, STARTOF(VRAM)
        jp Print
    ]]
    pop hl
    ret

تفاوت در این است که مثال استفاده‌کننده از لیترال‌های قطعه، ترتیب خاصی را برای اجزای خود اعلان نمی‌کند.

لیترال‌های قطعه می‌توانند به دلخواه تودرتو شوند، بنابراین موارد استفاده افراطی نیز از نظر فنی امکان‌پذیر است. این کد با استفاده از برچسب‌های نام‌گذاری‌شده:

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

معادل با این کد با استفاده از لیترال‌های قطعه است:

dw [[
    call [[
        Sub1: ld a, [ [[db 20]] ] :: ret
    ]]
    jr [[
        jp [[ call Sub1 :: inc a :: add a :: ret ]]
    ]]
]]

پروژه RGBDS از چندین نوع نماد پشتیبانی می‌کند:

برچسب (Label)
نماد عددی که یک مکان حافظه را مشخص می‌کند. ممکن است مقداری شناخته‌شده در زمان اسمبل داشته باشد یا نداشته باشد.
ثابت (Constant)
نماد عددی که مقدار آن باید در زمان اسمبل شناخته‌شده باشد.
ماکرو (Macro)
بلوکی از کد که بعداً می‌تواند فراخوانی شود.
رشته (String)
یک رشته متنی که بعداً می‌تواند مشابه یک ماکرو بسط داده شود.

نام‌های نمادها می‌توانند شامل حروف اسکی، اعداد، خط زیر ‘_ ،’ علامت هش ‘# ،’ علامت دلار ‘$ ،’ و علامت ات‌ساین ‘@’ باشند. با این حال، آن‌ها باید با یک حرف یا یک خط زیر آغاز شوند. علاوه بر این، نام‌های برچسب می‌توانند حداکثر شامل یک نقطه ‘.’ باشند که نباید نویسه اول باشد.

یک نماد نمی‌تواند همنام با یک کلمه کلیدی رزرو شده باشد، مگر اینکه نام آن یک “شناسه خام” با پیشوند هش ‘#’ باشد. به عنوان مثال، ‘#load’ نشان‌دهنده نمادی به نام ‘load’ است، و ‘#LOAD’ نشان‌دهنده نماد متفاوتی به نام ‘LOAD’ است؛ در هر دو مورد، ‘#’ از تلقی شدن آن‌ها به عنوان کلمه کلیدی LOAD جلوگیری می‌کند.

یکی از وظایف اصلی اسمبلر، پیگیری آدرس‌ها برای شماست، تا بتوانید به جای اعداد “جادویی” با نام‌های با معنی کار کنید. برچسب‌ها دقیقاً این امکان را فراهم می‌کنند: یک برچسب یک نام را به یک مکان خاص درون یک بخش پیوند می‌دهد. یک برچسب به یک بانک و آدرس ترجمه می‌شود که همزمان با بخش والد آن تعیین می‌گردد (ادامه این بخش را ببینید).

یک برچسب با نوشتن نام آن در ابتدای یک خط، به همراه یک یا دو دونقطه تعریف می‌شود، بدون هیچ فاصله خالی بین نام برچسب و دونقطه(ها). تعریف یک برچسب (سراسری یا محلی) با دو دونقطه ‘::’ آن را همزمان تعریف و صادر (EXPORT) می‌کند. (به صادر و وارد کردن نمادها (Exporting and importing symbols) در زیر مراجعه کنید). هنگام تعریف یک برچسب محلی، دونقطه می‌تواند حذف شود و طوری رفتار خواهد کرد که گویی تنها یک دونقطه وجود داشته است.

یک برچسب در صورتی محلی نامیده می‌شود که نام آن شامل یک نقطه ‘.’ باشد؛ در غیر این صورت، سراسری نامیده می‌شود (با “صادر شده ،” که در صادر و وارد کردن نمادها (Exporting and importing symbols) در زیر توضیح داده شده، اشتباه گرفته نشود). وجود بیش از یک نقطه در نام‌های برچسب مجاز نیست.

برای سهولت، برچسب‌های محلی می‌توانند از نحو خلاصه استفاده کنند: زمانی که نام نمادی که با نقطه شروع می‌شود یافت شود (به عنوان مثال، درون یک عبارت یا هنگام تعریف یک برچسب)، “حوزه برچسب” فعلی به طور ضمنی به ابتدای آن افزوده می‌شود.

تعریف یک برچسب سراسری، آن را به عنوان “حوزه برچسب” فعلی تنظیم می‌کند، تا زمانی که تعریف برچسب سراسری بعدی، یا پایان بخش فعلی فرا برسد.

در اینجا چند مثال از تعاریف برچسب آورده شده است:

GlobalLabel:
AnotherGlobal:
.locallabel ; This defines "AnotherGlobal.locallabel"
.another_local:
AnotherGlobal.with_another_local:
ThisWillBeExported:: ; Note the two colons
ThisWillBeExported.too::

در یک عبارت عددی، یک برچسب به آدرس خود در حافظه ارزیابی می‌شود. (برای به دست آوردن بانک آن، از تابع ‘BANK()’ توصیف شده در Other functions استفاده کنید). به عنوان مثال، با توجه به موارد زیر، ‘ld de, vPlayerTiles’ معادل ‘ld de, $80C0’ خواهد بود با فرض اینکه بخش در $80C0 قرار گیرد:

SECTION "Player tiles", VRAM
vPlayerTiles:
    ds 6 * 16
.end

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

همچنین، در حالی که بدیهی است می‌تواند تفاضل بین دو برچسب را در صورت ثابت بودن هر دو محاسبه کند، قادر است تفاضل بین دو برچسب غیرثابت را نیز در صورتی که هر دو به یک بخش تعلق داشته باشند، مانند ‘PlayerTiles’ و ‘PlayerTiles.end’ در بالا، محاسبه کند.

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

برچسب‌های ناشناس با استفاده از یک دونقطه ‘:’ به همراه علامت‌های مثبت ‘+’ یا منفی ‘-’ ارجاع داده می‌شوند. بنابراین :+ به برچسب بعدی پس از عبارت، :++ به برچسب بعد از آن؛ :- به برچسب قبلی قبل از عبارت ارجاع می‌دهد؛ و به همین ترتیب.

    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

یک علامت مساوی ‘=’ برای تعریف نمادهای عددی تغییرپذیر استفاده می‌شود. برخلاف سایر نمادهای توضیح داده شده در زیر، متغیرها می‌توانند دوباره تعریف شوند. این قابلیت برای نمادهای داخلی در ماکروها، شمارنده‌ها و غیره مفید است.

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

توجه داشته باشید که قرار دادن دونقطه ‘:’ پس از نام مجاز نیست.

متغیرها را می‌توان به راحتی با عملگرهای انتساب ترکیبی مانند C دوباره تعریف کرد:

عملگر معنی
جمع/تفریق ترکیبی
ضرب/تقسیم/باقی‌مانده ترکیبی
شیفت به چپ/راست ترکیبی
عملیات and/or/xor ترکیبی

مثال‌ها:

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

اعلان یک متغیر با EXPORT DEF یا EXPORT REDEF آن را همزمان تعریف و صادر (EXPORT) می‌کند. (به صادر و وارد کردن نمادها (Exporting and importing symbols) در زیر مراجعه کنید).

دستور EQU برای تعریف نمادهای ثابت عددی استفاده می‌شود. برخلاف ‘=’ در بالا، ثابت‌هایی که به این روش تعریف می‌شوند را نمی‌توان دوباره تعریف کرد. این ثابت‌ها می‌توانند برای مقادیر بدون تغییر مانند ویژگی‌های سخت‌افزار استفاده شوند.

def SCREEN_WIDTH  equ 160 ; In pixels
def SCREEN_HEIGHT equ 144

توجه داشته باشید که قرار دادن دونقطه ‘:’ پس از نام مجاز نیست.

اگر واقعاً نیاز دارید، کلمه کلیدی REDEF یک نماد ثابت عددی را تعریف یا دوباره تعریف می‌کند. (همچنین می‌توان از آن برای متغیرها استفاده کرد، اگرچه ضروری نیست زیرا آن‌ها خود تغییرپذیر هستند.) این می‌تواند به عنوان مثال برای به‌روزرسانی یک ثابت با استفاده از یک ماکرو، بدون تغییرپذیر کردن آن در حالت کلی، استفاده شود.

    def NUM_ITEMS equ 0
MACRO add_item
    redef NUM_ITEMS equ NUM_ITEMS + 1
    def ITEM_{02x:NUM_ITEMS} equ \1
ENDM
    add_item 1
    add_item 4
    add_item 9
    add_item 16
    assert NUM_ITEMS == 4
    assert ITEM_04 == 16

اعلان یک ثابت عددی با EXPORT DEF یا EXPORT REDEF آن را همزمان تعریف و صادر (EXPORT) می‌کند. (به صادر و وارد کردن نمادها (Exporting and importing symbols) در زیر مراجعه کنید).

گروه دستورات RS روشی مفید برای تعریف آفست‌های ساختار است:

               RSRESET
DEF str_pStuff RW   1
DEF str_tData  RB   256
DEF str_bCount RB   1
DEF str_SIZEOF RB   0

این مثال چهار ثابت را تعریف می‌کند گویی که به شکل زیر تعریف شده باشند:

DEF str_pStuff EQU 0
DEF str_tData  EQU 2
DEF str_bCount EQU 258
DEF str_SIZEOF EQU 259

پنج دستور در گروه دستورات RS وجود دارد:

دستور معنی
معادل ‘RSSET 0’.
constexpr شمارنده _RS را روی constexpr تنظیم می‌کند.
name RB constexpr مقدار name را برابر _RS قرار می‌دهد و سپس constexpr را به _RS اضافه می‌کند.
name RW constexpr مقدار name را برابر _RS قرار می‌دهد و سپس constexpr * 2 را به _RS اضافه می‌کند.
name RL constexpr مقدار name را برابر _RS قرار می‌دهد و سپس constexpr * 4 را به _RS اضافه می‌کند.

اگر آرگومان constexpr برای RB ، RW ، یا RL حذف شود، مقدار آن 1 فرض می‌شود.

توجه داشته باشید که قرار دادن دونقطه ‘:’ پس از نام مجاز نیست.

اعلان یک ثابت آفست با EXPORT DEF آن را همزمان تعریف و صادر (EXPORT) می‌کند. (به صادر و وارد کردن نمادها (Exporting and importing symbols) در زیر مراجعه کنید).

دستور EQUS برای تعریف نمادهای ثابت رشته‌ای استفاده می‌شود. هر جا که اسمبلر یک ثابت رشته‌ای را بخواند، آن نماد بسط داده می‌شود: نام نماد با محتوای آن جایگزین می‌شود، مشابه #define در زبان برنامه‌نویسی C. این بسط در چند زمینه غیرفعال است: ‘DEF(name) ،’ ‘DEF name EQU/=/EQUS/etc ... ،’ ‘REDEF name EQU/=/EQUS/etc ... ،’ ‘FOR name, ... ،’ ‘PURGE name ،’ و ‘MACRO name’ ثابت‌های رشته‌ای را در نام‌های خود بسط نخواهند داد. بسط همچنین در صورتی که نام ثابت رشته‌ای یک شناسه خام با پیشوند هش ‘#’ باشد، غیرفعال است.

DEF COUNTREG EQUS "[hl+]"
    ld a, COUNTREG

DEF PLAYER_NAME EQUS "\"John\""
    db PLAYER_NAME

این به صورت زیر تفسیر خواهد شد:

ld a, [hl+]
db "John"

ثابت‌های رشته‌ای همچنین می‌توانند برای تعریف ماکروهای کوچک تک‌خطی استفاده شوند:

DEF pusha EQUS "push af\npush bc\npush de\npush hl\n"

توجه داشته باشید که قرار دادن دونقطه ‘:’ پس از نام مجاز نیست.

ثابت‌های رشته‌ای، مانند ثابت‌های عددی، نمی‌توانند دوباره تعریف شوند. با این حال، کلمه کلیدی REDEF یک نماد ثابت رشته‌ای را تعریف یا دوباره تعریف می‌کند. به عنوان مثال:

DEF s EQUS "Hello, "
REDEF s EQUS "{s}world!"
; prints "Hello, world!"
PRINTLN "{s}\n"

ثابت‌های رشته‌ای را نمی‌توان صادر یا وارد کرد.

نکته مهم: هنگامی که یک ثابت رشته‌ای بسط داده می‌شود، بسط آن ممکن است شامل ثابت رشته‌ای دیگری باشد که آن نیز بسط داده خواهد شد و ممکن است بازگشتی باشد. اگر این امر یک حلقه بی‌نهایت ایجاد کند، پس از رسیدن به یک عمق معین با خطا متوقف می‌شود (گزینه خط فرمان -r در rgbasm(1) را ببینید). همین مشکل در صورتی که بسط یک ثابت رشته‌ای ماکرویی را فراخوانی کند که خود بسط می‌یابد، می‌تواند رخ دهد.

یکی از بهترین ویژگی‌های یک اسمبلر توانایی نوشتن ماکروها برای آن است. ماکروها را می‌توان با آرگومان‌ها فراخوانی کرد و آن‌ها می‌توانند بسته به ورودی با استفاده از ساختارهای IF واکنش نشان دهند.

MACRO my_macro
    ld a, 80
    call MyFunc
ENDM

مثال بالا ‘my_macro’ را به عنوان یک ماکروی جدید تعریف می‌کند. ثابت‌های رشته‌ای در نام ماکرو بسط داده نمی‌شوند.

ماکروها را نمی‌توان صادر یا وارد کرد.

تودرتو کردن تعاریف ماکرو امکان‌پذیر نیست، بنابراین این مورد کار نخواهد کرد:

MACRO outer
    MACRO inner
        PRINTLN "Hello!"
    ENDM ; this actually ends the 'outer' macro...
ENDM     ; ...and then this is a syntax error!

اما می‌توانید با استفاده از EQUS این محدودیت را دور بزنید، بنابراین این مورد کار خواهد کرد:

MACRO outer
    DEF definition EQUS "MACRO inner\nPRINTLN \"Hello!\"\nENDM"
    definition
    PURGE definition
ENDM

اطلاعات بیشتر درباره نحوه تعریف و فراخوانی ماکروها در زبان ماکرو (THE MACRO LANGUAGE) در زیر توضیح داده شده است.

وارد و صادر کردن نمادها قابلیتی است که وقتی پروژه شما چندین فایل منبع را در بر می‌گیرد، بسیار مفید است؛ به عنوان مثال، زمانی که نیاز دارید به روال تعریف‌شده در فایل دیگری پرش کنید.

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

دستور زیر باعث می‌شود symbol1 ، symbol2 و غیره در طول فرآیند پیوند برای فایل‌های دیگر قابل دسترسی باشند:

EXPORT symbol1 [, symbol2, ...]

به عنوان مثال، اگر سه فایل زیر را داشته باشید:

‘a.asm’:

SECTION "a", WRAM0
LabelA:

‘b.asm’:

SECTION "b", WRAM0
ExportedLabelB1::
ExportedLabelB2:
    EXPORT ExportedLabelB2

‘c.asm’:

SECTION "C", ROM0[0]
    dw LabelA
    dw ExportedLabelB1
    dw ExportedLabelB2

آنگاه ‘c.asm’ می‌تواند از ‘ExportedLabelB1’ و ‘ExportedLabelB2’ استفاده کند، اما نمی‌تواند از ‘LabelA’ استفاده کند، بنابراین پیوند دادن آن‌ها با یکدیگر شکست خواهد خورد:

$ 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

دستور PURGE به شما امکان می‌دهد یک نماد را کاملاً از جدول نمادها حذف کنید، گویی که هرگز تعریف نشده است.

DEF value EQU 42
PURGE value
DEF value EQUS "I'm a string now"
ASSERT DEF(value)
PURGE value
ASSERT !DEF(value)

هنگام پاک‌سازی نمادهایی که در داده‌های بخش ارجاع داده شده‌اند، یا صادر شده‌اند، بسیار مراقب باشید، زیرا اگر چیزی به نماد گمشده وابسته باشد (به عنوان مثال، عباراتی که پیونددهنده نیاز به محاسبه آن‌ها دارد)، ممکن است منجر به خطاهای غیرقابل پیش‌بینی شود. پاک‌سازی برچسب‌ها به هیچ وجه توصیه نمی‌شود.

ثابت‌های رشته‌ای درون نام‌های نماد بسط داده نمی‌شوند.

نمادهای زیر توسط اسمبلر تعریف شده‌اند:

نام نوع محتویات
مقدار PC (اساساً، آدرس حافظه فعلی)
. حوزه برچسب سراسری فعلی
حوزه برچسب محلی فعلی
درونی‌ترین سطح حوزه برچسب فعلی (خالی،. ، یا ..)
شمارنده _RS
تعداد آرگومان‌های ارسالی به ماکرو، به‌روزرسانی شده توسط SHIFT
برچسب زمانی ISO 8601 (محلی)
برچسب زمانی ISO 8601 (UTC)
سال جاری
شماره ماه جاری، 1–12
روز جاری از ماه، 1–31
ساعت فعلی، 0–23
دقیقه فعلی، 0–59
ثانیه فعلی، 0–59
شماره نسخه اصلی RGBDS
شماره نسخه فرعی RGBDS
شماره نسخه وصله RGBDS
شناسه نامزد انتشار RGBDS، برای نسخه‌های نهایی تعریف نشده است
نسخه RGBDS، همانطور که توسط ‘rgbasm --version چاپ می‌شود’

مقادیر زمان فعلی از متغیر محیطی SOURCE_DATE_EPOCH در صورتی که به عنوان یک برچسب زمانی یونیکس تعریف شده باشد، گرفته خواهد شد. به مشخصات در reproducible-builds.org مراجعه کنید.

دستور DB فهرستی از بایت‌ها را تعریف می‌کند که در تصویر نهایی ذخیره خواهند شد. ایده‌آل برای جدول‌ها و متن.

DB 1,2,3,4,"This is a string"

همچنین، می‌توانید از DW برای ذخیره فهرستی از کلمات (16 بیتی) یا از DL برای ذخیره فهرستی از کلمات مضاعف/طولانی (32 بیتی) استفاده کنید. هر دوی این دستورات داده‌های خود را با ترتیب بایت اندیان کوچک (little-endian) می‌نویسند؛ به عنوان مثال، ‘dw $CAFE’ معادل ‘db $FE, $CA’ است و نه ‘db $CA, $FE’.

رشته‌ها تا حدودی به طور ویژه مدیریت می‌شوند: آن‌ها ابتدا تحت تبدیل نگاشت نویسه قرار می‌گیرند (به Character maps مراجعه کنید)، سپس هر نویسه حاصل به صورت مجزا خروجی داده می‌شود. به عنوان مثال، تحت نگاشت نویسه پیش‌فرض، دو خط زیر یکسان هستند:

DW "Hello!"
DW "H", "e", "l", "l", "o", "!"

اگر این رفتار ویژه را نمی‌خواهید، رشته را در پرانتز قرار دهید.

دستور DS همچنین می‌تواند برای پر کردن ناحیه‌ای از حافظه با مقادیر تکراری استفاده شود. به عنوان مثال:

; outputs 3 bytes: $AA, $AA, $AA
DS 3, $AA
; outputs 7 bytes: $BB, $CC, $BB, $CC, $BB, $CC, $BB
DS 7, $BB, $CC

همچنین می‌توانید از DB ، DW و DL بدون آرگومان استفاده کنید. این دقیقاً مانند DS 1 ، DS 2 و DS 4 به ترتیب عمل می‌کند. در نتیجه، DB ، DW و DL بدون آرگومان را می‌توان در بخش‌های WRAM0 / WRAMX / HRAM / VRAM / SRAM استفاده کرد.

شما احتمالاً داده‌های گرافیکی، مراحل بازی و غیره دارید که مایلید آن‌ها را شامل کنید. از INCBIN برای شامل کردن یک فایل دودویی خام همان‌طور که هست استفاده کنید. اگر فایل در دایرکتوری فعلی یافت نشود، فهرست مسیرهای شامل‌سازی ارائه‌شده به گزینه -I دستور rgbasm(1) در خط فرمان جستجو خواهد شد.

INCBIN "titlepic.bin"
INCBIN "sprites/hero.bin"

همچنین می‌توانید تنها بخشی از یک فایل را با INCBIN شامل کنید. مثال زیر 256 بایت از data.bin را با شروع از بایت 78 شامل می‌کند.

INCBIN "data.bin", 78, 256

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

دستور DS تعداد مشخصی بایت خالی را به صورت ایستا تخصیص می‌دهد. این روش ترجیحی برای تخصیص فضا در یک بخش RAM است. همچنین می‌توانید به جای آن از DB ، DW و DL بدون هیچ آرگومانی استفاده کنید (به تعریف داده‌های ثابت در ROM (Defining constant data in ROM) در زیر مراجعه کنید).

DS 42 ; Allocates 42 bytes

فضای خالی در بخش‌های RAM مقداردهی اولیه نخواهد شد. در بخش‌های ROM، با مقدار ارسال‌شده به گزینه خط فرمان -p پر خواهد شد، به جز هنگام استفاده از هم‌پوشانی‌ها با -O.

به جای تعداد دقیق بایت‌ها، می‌توانید ALIGN[align, offset] را مشخص کنید تا هر تعداد بایت که برای تراز کردن داده‌های بعدی لازم است تخصیص یابد. بنابراین، ‘DS ALIGN[align, offset], ...’ معادل ‘DS n, ...’ به دنبال ‘ALIGN[align, offset]’ است، که در آن n حداقل مقدار مورد نیاز برای برآورده کردن محدودیت ALIGN است (به درخواست تراز (Requesting alignment) در زیر مراجعه کنید). توجه داشته باشید که ALIGN[align] کوتاه‌شده‌ای برای ALIGN[align, 0] است.

یونیون‌ها به چندین تخصیص حافظه ایستا اجازه همپوشانی می‌دهند، مانند union در زبان C. این امر مقدار حافظه در دسترس را افزایش نمی‌دهد، اما اجازه می‌دهد از همان ناحیه حافظه برای اهداف مختلف دوباره استفاده شود.

یک یونیون با کلمه کلیدی UNION شروع می‌شود و با کلمه کلیدی متناظر ENDU پایان می‌یابد. دستور NEXTU هر بلوک از تخصیص‌ها را جدا می‌کند، و می‌توانید هر تعداد بار که در یک یونیون لازم است از آن استفاده کنید.

; 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

در مثال بالا، ‘wName ، wHealth ،’ و ‘wVideoBuffer’ همگی مقدار یکسانی دارند؛ همینطور ‘wNickname’ و ‘wBonus’. بنابراین به خاطر داشته باشید که ‘ld [wHealth], a’ دقیقاً به همان دستور ‘ld [wName], a’ اسمبل می‌شود.

اندازه کل این یونیون 20 بایت است، یعنی اندازه بزرگترین بلوک (اولین بلوک، شامل ‘wName’ و ‘wNickname’).

یونیون‌ها ممکن است تودرتو باشند، به طوری که اندازه هر یونیون درونی طبق روش بالا تعیین می‌شود و مانند هر تخصیص دیگری روی یونیون بیرونی تأثیر می‌گذارد.

یونیون‌ها را می‌توان در هر بخشی استفاده کرد، اما آن‌ها فقط می‌توانند شامل دستورالعمل‌های تخصیص فضا مانند DS باشند (به تخصیص ایستا فضا در RAM (Statically allocating space in RAM) مراجعه کنید).

در حالی که دستور ALIGN همانطور که در SECTIONS معرفی شد اغلب به همان شکل مفید است، گاهی اوقات به جای آن می‌خواهید یک قطعه داده (یا کد) خاص در میانه بخش تراز شود. این کار از طریق استفاده از ALIGN align, offset در میانه بخش آسان‌تر شده است. این دستور ویژگی‌های بخش را عطف‌به‌ماسبق تغییر می‌دهد تا اطمینان حاصل شود مکانی که دستورالعمل ALIGN در آن قرار دارد، align بیت پایین‌تر آن برابر با offset باشد.

اگر این محدودیت نتواند برآورده شود (برای مثال به دلیل اینکه بخش در یک آدرس ناسازگار ثابت شده است)، خطایی ایجاد می‌شود. توجه داشته باشید که ALIGN align کوتاه‌شده‌ای برای ALIGN align, 0 است.

ممکن است زمان‌هایی وجود داشته باشد که نه‌تنها بخواهید یک محدودیت تراز را در مکان فعلی مشخص کنید، بلکه بخواهید تا زمانی که محدودیت برآورده شود به جلو بروید. در این حالت، می‌توانید از DS ALIGN[align, offset] برای تخصیص هر تعداد بایت که برای تراز کردن داده‌های بعدی لازم است استفاده کنید.

اگر با پرش از هر مقدار فضا نتوان محدودیت را برآورده کرد، خطایی ایجاد می‌شود. توجه داشته باشید که ALIGN[align] کوتاه‌شده‌ای برای ALIGN[align, 0] است.

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

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

پس از اینکه خط فراخوانی ماکرو را خواند، بدنه ماکرو (خطوط بین MACRO و ENDM) را در جای آن بسط می‌دهد.

نکته مهم: هنگامی که بدنه یک ماکرو بسط می‌یابد، بسط آن ممکن است شامل فراخوانی ماکروی دیگری باشد که آن نیز بسط داده خواهد شد و ممکن است بازگشتی باشد. اگر این امر یک حلقه بی‌نهایت ایجاد کند، پس از رسیدن به یک عمق معین با خطا متوقف می‌شود (گزینه خط فرمان -r در rgbasm(1) را ببینید). همین مشکل ممکن است در صورتی که بسط یک ماکرو سپس یک ثابت رشته‌ای را بسط دهد که خود بسط می‌یابد، رخ دهد.

ارسال آرگومان‌ها به ماکروها نیز امکان‌پذیر است!

MACRO lb
    ld \1, (\2) << 8 | (\3)
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)"

شما آرگومان‌ها را درون بدنه ماکرو با استفاده از دنباله‌های گریز \1 تا \9 بسط می‌دهید؛ \1 اولین آرگومان است، \2 دومین آرگومان، و به همین ترتیب. از آنجا که تنها نه رقم وجود دارد، شما فقط می‌توانید از نه آرگومان اول ماکرو به این شکل استفاده کنید. برای استفاده از بقیه، شماره آرگومان را در قلاب‌های شکسته قرار می‌دهید، مانند \<10>.

این نحو قلاب‌دار از اعداد ده‌دهی و نمادهای عددی پشتیبانی می‌کند، جایی که مقادیر منفی از آخرین آرگومان شمارش می‌شوند. به عنوان مثال، ‘\<_NARG>’ یا ‘\<-1>’ آخرین آرگومان را دریافت خواهد کرد.

سایر آرگومان‌های ماکرو و درون‌یابی‌های نماد نیز درون قلاب‌های شکسته بسط داده خواهند شد. به عنوان مثال، اگر ‘\1’ برابر با ‘13’ باشد، آنگاه ‘\<\1>’ درون بدنه ماکرو به ‘\<13>’ بسط می‌یابد. یا اگر ‘DEF v10 = 42’ و ‘DEF x = 10’ باشد، آنگاه ‘\<v{d:x}>’ به ‘\<42>’ بسط خواهد یافت.

آرگومان‌های ماکرو به صورت ثابت‌های رشته‌ای ارسال می‌شوند، اگرچه نیازی به قرار دادن آن‌ها درون علامت نقل‌قول نیست. بنابراین، آرگومان‌ها به عنوان عبارت ارزیابی نمی‌شوند، بلکه مستقیماً درون بدنه ماکرو بسط می‌یابند. این بدان معنی است که آن‌ها از تمام دنباله‌های گریز رشته‌ها پشتیبانی می‌کنند (به String expressions در بالا مراجعه کنید)، و همچنین برخی از دنباله‌های خاص خود را دارند:

دنباله معنی
‘\,’ ویرگول (آرگومان را خاتمه نمی‌دهد)
‘\(’ پرانتز باز (محتوای آرگومان را محصور نمی‌کند)
‘\)’ پرانتز بسته (محتوای آرگومان را خاتمه نمی‌دهد)

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

MACRO PrintMacro1
    PRINTLN STRCAT(\1)
ENDM
    PrintMacro1 "Hello "\, \
                "world"
MACRO PrintMacro2
    PRINT \1
ENDM
    PrintMacro2 STRCAT("Hello ", \
                       "world\n")

ویرگول در ‘PrintMacro1’ باید گریز داده شود تا از شروع یک آرگومان ماکروی دیگر جلوگیری کند. ویرگول در ‘PrintMacro2’ نیازی به گریز ندارد زیرا داخل پرانتز است، مشابه آرگومان‌های ماکرو در زبان برنامه‌نویسی C. بک‌اسلش در ‘\n’ نیز نیازی به گریز ندارد زیرا لیترال‌های رشته‌ای نقل‌قول‌شده طبق معمول درون آرگومان‌های ماکرو کار می‌کنند.

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

MACRO print_double
    PRINTLN \1 * 3
ENDM
    print_double 1 + 2

بدنه به ‘PRINTLN 1 + 2 * 3’ بسط خواهد یافت که مقدار 7 را چاپ می‌کند و نه 9 همانطور که ممکن است انتظار داشته باشید.

دستورالعمل SHIFT فقط درون بدنه ماکروها در دسترس است. این دستور شماره‌های آرگومان را یک واحد به سمت چپ منتقل می‌کند، بنابراین آنچه \2 بود اکنون \1 است، آنچه \3 بود اکنون \2 است، و به همین ترتیب. (آنچه \1 بود دیگر در دسترس نیست، بنابراین _NARG به اندازه 1 کاهش می‌یابد.)

دستور SHIFT همچنین می‌تواند یک پارامتر عدد صحیح بگیرد تا به جای یک بار، به آن تعداد دفعات شیفت را انجام دهد. یک پارامتر منفی آرگومان‌ها را به سمت راست شیفت می‌دهد که می‌تواند دسترسی به موارد شیفت‌داده‌شده قبلی را دوباره به دست آورد.

دستور SHIFT به ویژه در حلقه‌های REPT برای تکرار روی آرگومان‌های مختلف و ارزیابی همان بدنه حلقه در هر بار بسیار مفید است.

چندین دنباله گریز وجود دارند که فقط درون بدنه یک ماکرو معتبر هستند:

دنباله معنی
‘\1’ – ‘\9’ آرگومان‌های اول–نهم ماکرو
‘\<...>’ آرگومان‌های بعدی ماکرو
‘\#’ همه آرگومان‌های _NARG ماکرو، جدا شده با ویرگول
‘\@’ پسوند نام نماد یکتا (زیر را ببینید)

دنباله گریز \@ اغلب در ماکروهایی که نمادها را تعریف می‌کنند مفید است. فرض کنید ماکروی شما به یک حلقه از کد اسمبلی بسط می‌یابد:

MACRO loop_c_times
    xor a, a
.loop
    ld [hl+], a
    dec c
    jr nz, .loop
ENDM

اگر از این ماکرو بیش از یک بار در همان حوزه برچسب استفاده کنید، ‘.loop’ را دو بار تعریف می‌کند که یک خطا است. برای رفع این مشکل، می‌توانید از \@ به عنوان پسوند برچسب استفاده کنید:

MACRO loop_c_times_fixed
    xor a, a
.loop\@
    ld [hl+], a
    dec c
    jr nz, .loop\@
ENDM

این در هر فراخوانی به مقدار متفاوتی بسط می‌یابد، مشابه gensym در زبان برنامه‌نویسی Lisp.

همچنین \@ در بلوک‌های REPT کار می‌کند، و در هر تکرار به مقدار متفاوتی بسط می‌یابد.

فرض کنید می‌خواهید یک حلقه وقت‌گیر را بدون کپی و چسباندن آن باز کنید (unroll کنید). دستور REPT برای این منظور فراهم شده است. همه چیز بین REPT و ENDR متناظر، به تعداد مشخصی تکرار خواهد شد، درست مانند اینکه خودتان عملیات کپی/چسباندن را انجام داده باشید. مثال زیر ‘add a, c’ را چهار بار اسمبل می‌کند:

REPT 4
    add a, c
ENDR

همچنین می‌توانید از REPT برای تولید جدول‌ها به صورت بلادرنگ استفاده کنید:

; 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

همانند ماکروها، می‌توانید از دنباله گریز \@ نیز استفاده کنید. بلوک‌های REPT می‌توانند تودرتو باشند.

یک الگوی رایج، تکرار یک بلوک به ازای هر مقدار در یک محدوده خاص است. دستور FOR برای این هدف ساده‌تر از REPT است. همه چیز بین FOR و ENDR متناظر برای هر مقدار از یک نماد داده‌شده تکرار خواهد شد. ثابت‌های رشته‌ای درون نام نماد بسط داده نمی‌شوند. به عنوان مثال، این کد جدولی از مقادیر مربع از 0 تا 255 تولید می‌کند:

FOR N, 256
    dw N * N
ENDR

این دستور دقیقاً طوری عمل می‌کند که گویی چنین کدی نوشته‌اید:

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

می‌توانید محدوده مقادیر FOR را سفارشی کنید، مشابه تابع ‘range’ در زبان برنامه‌نویسی Python:

کد محدوده
V, stop V از 0 تا stop افزایش می‌یابد
V, start, stop V از start تا stop افزایش می‌یابد
V, start, stop, step V از start تا stop با گام step پیش می‌رود

مقدار FOR با step به‌روزرسانی می‌شود تا زمانی که به stop برسد یا از آن فراتر رود، یعنی محدوده نیمه‌باز از start (شامل) تا stop (غیرشامل) را پوشش می‌دهد. متغیر V در ابتدای هر تکرار جدید به این مقدار اختصاص می‌یابد؛ هرگونه تغییری که در بدنه حلقه FOR در آن ایجاد شود بازنویسی خواهد شد. بنابراین نماد V لازم نیست قبل از هر تکرار حلقه FOR از قبل تعریف شده باشد، اما اگر تعریف شده باشد باید یک متغیر (متغیرها (Variables)) باشد. به عنوان مثال:

FOR V, 4, 25, 5
    PRINT "{d:V} "
    DEF V *= 2
ENDR
    PRINTLN "done {d:V}"

این قطعه کد خروجی زیر را چاپ می‌کند:

4 9 14 19 24 done 29

درست مانند بلوک‌های REPT ، می‌توانید از دنباله گریز \@ درون بلوک‌های FOR استفاده کنید، و آن‌ها می‌توانند تودرتو باشند.

می‌توانید یک بلوک تکرار را با دستور BREAK متوقف کنید. دستور BREAK درون یک بلوک REPT یا FOR تکرار فعلی را قطع می‌کند و دیگر تکرار نخواهد شد. این دستور اجرای کد را پس از ENDR بلوک ادامه خواهد داد. به عنوان مثال:

FOR V, 1, 100
    PRINT "{d:V}"
    IF V == 5
        PRINT " stop! "
        BREAK
    ENDC
    PRINT ", "
ENDR
    PRINTLN "done {d:V}"

این خروجی زیر را چاپ می‌کند:

1, 2, 3, 4, 5 stop! done 5

چهار دستور IF ، ELIF ، ELSE ، و ENDC به شما امکان می‌دهند بسته به یک شرط، بخش‌هایی از کد خود را توسط نادیده بگیرید. این یک قابلیت قدرتمند است که معمولاً در ماکروها استفاده می‌شود.

IF NUM < 0
  PRINTLN "NUM < 0"
ELIF NUM == 0
  PRINTLN "NUM == 0"
ELSE
  PRINTLN "NUM > 0"
ENDC

بلوک‌های ELIF (کوتاه‌شده "else if") و ELSE اختیاری هستند. بلوک‌های IF / ELIF / ELSE / ENDC می‌توانند تودرتو باشند.

توجه داشته باشید که اگر یک بلوک ELSE قبل از یک بلوک ELIF یافت شود، بلوک ELIF نادیده گرفته خواهد شد. تمام بلوک‌های ELIF باید قبل از بلوک ELSE قرار گیرند. همچنین، اگر بیش از یک بلوک ELSE وجود داشته باشد، همه آن‌ها به جز اولین مورد نادیده گرفته می‌شوند.

از INCLUDE برای پردازش یک فایل اسمبلی دیگر و سپس بازگشت به فایل فعلی پس از اتمام استفاده کنید. اگر فایل در دایرکتوری فعلی یافت نشود، فهرست مسیرهای شامل‌سازی ارائه‌شده به گزینه -I دستور rgbasm(1) در خط فرمان جستجو خواهد شد. شما می‌توانید فراخوانی‌های INCLUDE را به صورت نامحدود تودرتو کنید (یا تا زمانی که حافظه تمام شود، هر کدام که زودتر رخ دهد).

INCLUDE "irq.inc"

همچنین می‌توانید قبل از فایل منبع، فایلی را به طور ضمنی با استفاده از گزینه -P در rgbasm(1) شامل (INCLUDE) کنید.

دستورات PRINT و PRINTLN متن و مقادیر را در خروجی استاندارد چاپ می‌کنند. برای اشکال‌زدایی ماکروها یا هر جایی که احساس نیاز به اعلام اطلاعات مهمی به خود داشته باشید مفید است.

PRINT "Hello world!\n"
PRINTLN "Hello world!"
PRINT _NARG, " arguments\n"
PRINTLN "sum: ", 2+3, " product: ", 2*3
PRINTLN STRFMT("E = %f", 2.718)
هر یک از آرگومان‌های جدا شده با ویرگول خود را چاپ می‌کند. اعداد به صورت هگزادسیمال بزرگ بدون علامت به همراه یک پیشوند ‘$’ چاپ می‌شوند. برای قالب‌های مختلف، از STRFMT استفاده کنید.
هر یک از آرگومان‌های جدا شده با ویرگول خود را، در صورت وجود، به دنبال یک خط جدید (‘\n’) چاپ می‌کند.

دستورات FAIL و WARN می‌توانند به ترتیب برای چاپ خطاها و هشدارها در طول فرآیند اسمبل استفاده شوند. این به ویژه برای ماکروهایی که یک آرگومان نامعتبر دریافت می‌کنند مفید است. FAIL و WARN یک رشته را به عنوان تنها آرگومان می‌پذیرند و این رشته را به عنوان یک خطای معمولی همراه با شماره خط چاپ می‌کنند.

دستور FAIL بلافاصله اسمبل کردن را متوقف می‌کند در حالی که WARN پیام را نمایش می‌دهد اما پس از آن ادامه می‌دهد.

اگر نیاز دارید هنگام کامپایل از صحت فرضیه‌ای اطمینان حاصل کنید، می‌توانید از ASSERT و STATIC_ASSERT استفاده کنید. مثال‌های نحوی در زیر آورده شده است:

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!"

اولاً، تفاوت بین ASSERT و STATIC_ASSERT این است که اولی در صورت امکان توسط RGBASM ارزیابی می‌شود، در غیر این صورت توسط RGBLINK؛ اما دومی فقط و فقط توسط RGBASM ارزیابی می‌شود. اگر RGBASM نتواند مقدار آرگومان را برای STATIC_ASSERT محاسبه کند، خطایی ایجاد می‌کند.

ثانیاً، همانطور که در بالا نشان داده شده است، یک رشته می‌تواند به صورت اختیاری در انتها اضافه شود تا بینشی درباره آنچه که ادعا (assertion) در حال بررسی آن است ارائه دهد.

در نهایت، می‌توانید یکی از گزینه‌های WARN ، FAIL یا FATAL را به عنوان اولین آرگومان اختیاری به ASSERT یا STATIC_ASSERT اضافه کنید. اگر ادعا شکست بخورد، WARN باعث صدور یک هشدار ساده (کنترل شده توسط پرچم -Wassert در rgbasm(1)) می‌شود؛ FAIL (حالت پیش‌فرض) باعث یک خطای غیرکشنده می‌شود؛ و FATAL بلافاصله فرآیند را سقط می‌کند.

دستور OPT می‌تواند برای تغییر برخی از گزینه‌ها در طول اسمبل از درون منبع، به جای تعریف آن‌ها در خط فرمان، استفاده شود. (rgbasm(1) را ببینید).

دستور OPT فهرستی از گزینه‌ها را که با ویرگول از هم جدا شده‌اند به عنوان آرگومان خود می‌پذیرد:

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

دستور OPT می‌تواند گزینه‌های b ، g ، p ، Q ، r ، و W را تغییر دهد.

دستورات POPO و PUSHO رابط کاربری پشته گزینه‌ها را فراهم می‌کنند. PUSHO مجموعه فعلی گزینه‌ها را در پشته گزینه‌ها قرار می‌دهد (push می‌کند). سپس بعداً می‌توان از POPO برای بازیابی آن‌ها استفاده کرد. این قابلیت زمانی مفید است که بخواهید برخی گزینه‌ها را در یک فایل شامل‌شده تغییر دهید و نخواهید گزینه‌های تنظیم‌شده توسط برنامه‌ای که فایل شما را شامل کرده است از بین ببرید. تعداد ورودی‌های پشته تنها با میزان حافظه سیستم شما محدود می‌شود.

دستور PUSHO همچنین می‌تواند فهرستی از گزینه‌ها را که با ویرگول از هم جدا شده‌اند دریافت کند تا مجموعه فعلی را ذخیره کرده و همزمان مجموعه آرگومان‌ها را اعمال کند:

PUSHO b.#, g.oO#
    DB %..####..
    DW `..ooOO##
POPO

خطاها و هشدارها ردیابی پشته (backtraces) را چاپ می‌کنند که مکان رخ دادن مشکل در فایل منبع را نشان می‌دهد، و منشأ مشکل را حتی از طریق زنجیره‌ای از مکان‌های REPT ، FOR ، MACRO ، و INCLUDE ردیابی می‌کند. گاهی اوقات مکان‌هایی وجود دارند که مایلید نادیده بگیرید؛ به عنوان مثال، یک ماکروی کاربردی رایج هنگامی که فقط به خطی که ماکرو در آن استفاده شده اهمیت می‌دهید، یا یک فایل INCLUDE که فقط برای شامل کردن سایر فایل‌ها به کار می‌رود و صرفاً پرکننده در ردیابی پشته است.

در این موارد، می‌توانید با یک علامت سؤال ‘?’ بعد از نشانه (token)، یک مکان را ساکت کنید: تمام مکان‌های ایجاد شده توسط ‘REPT? ،’ ‘FOR? ،’ یا ‘MACRO?’ چاپ نخواهند شد، و هر مکانی که توسط یک ‘INCLUDE? ،’ یا فراخوانی ماکرویی که نام آن بلافاصله با یک ‘?’ دنبال شود، چاپ نخواهد شد. به عنوان مثال، اگر این قطعه کد به صورت ‘example.asm’ اسمبل شود:

MACRO lb
    assert -128 <= (\2) && (\2) < 256, "\2 is not a byte"
    assert -128 <= (\3) && (\3) < 256, "\3 is not a byte"
    ld \1, (LOW(\2) << 8) | LOW(\3)
ENDM
SECTION "Code", ROM0
    lb hl, $123, $45

این یک ردیابی پشته خطا چاپ می‌کند:

error: Assertion failed: $123 is not a byte
    at example.asm::lb(2)
    <- example.asm(7)

اما اگر ‘MACRO’ به ‘MACRO?’ تغییر یابد، یا ‘lb hl’ به ‘lb? hl’ تغییر یابد، آنگاه ردیابی پشته خطا مکانی درون ماکروی ‘lb’ را ذکر نخواهد کرد:

error: Assertion failed: $123 is not a byte
    at example.asm(7)

rgbasm(1), rgblink(1), rgblink(5), rgbfix(1), rgbgfx(1), gbz80(7), rgbasm-old(5), rgbds(5), rgbds(7)

دستور rgbasm(1) در ابتدا توسط Carsten Sørensen به عنوان بخشی از بسته ASMotor نوشته شد و بعداً در RGBDS توسط Justin Lloyd دوباره بسته‌بندی شد. اکنون توسط تعدادی از مشارکت‌کنندگان در https://github.com/gbdev/rgbds نگهداری می‌شود.

August 1, 2026 Linux 6.12.107+deb13-amd64