diff --git a/ci/ciimage/arch/install.sh b/ci/ciimage/arch/install.sh index 8f5245149688..1189caadba52 100755 --- a/ci/ciimage/arch/install.sh +++ b/ci/ciimage/arch/install.sh @@ -15,6 +15,7 @@ pkgs=( doxygen vulkan-validation-layers openssh mercurial gtk-sharp-2 qt5-tools libwmf cmake netcdf-fortran openmpi nasm gnustep-base gettext python-lxml hotdoc rust-bindgen qt6-base qt6-tools wayland wayland-protocols + rgbds # cuda ) diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index a5d0d5cdcc18..151579697d73 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -49,6 +49,7 @@ These are return values of the `get_id` (Compiler family) and | armasm | Microsoft Macro Assembler for ARM and AARCH64 (Since 0.64.0) | | | mwasmarm | Metrowerks Assembler for Embedded ARM | | | mwasmeppc | Metrowerks Assembler for Embedded PowerPC | | +| rgbds | Rednex GameBoy Development System | | ## Linker ids @@ -80,6 +81,7 @@ These are return values of the `get_linker_id` method in a compiler object. | ccomp | CompCert used as the linker driver | | mwldarm | The Metrowerks Linker with the ARM interface, used with mwccarm only | | mwldeppc | The Metrowerks Linker with the PowerPC interface, used with mwcceppc only | +| rgbds | Rednex GameBoy Development System | For languages that don't have separate dynamic linkers such as C# and Java, the `get_linker_id` will return the compiler name. @@ -132,6 +134,7 @@ set in the cross file. | s390 | IBM zSystem s390 | | s390x | IBM zSystem s390x | | sh4 | SuperH SH-4 | +| sm83 | Sharp SM83 (GB/GBC) | | sparc | 32 bit SPARC | | sparc64 | SPARC v9 processor | | sw_64 | 64 bit sunway processor | diff --git a/docs/markdown/snippets/rgbds_language_support.md b/docs/markdown/snippets/rgbds_language_support.md new file mode 100644 index 000000000000..21c191bd1f8d --- /dev/null +++ b/docs/markdown/snippets/rgbds_language_support.md @@ -0,0 +1,9 @@ +## Basic support for RGBDS assembly + +Meson now provides basic support for the assembly +and linking of Game Boy and Game Boy Color games +with RGBDS. + +Most projects will still need to call `rgbfix` as +a `custom_target` as this time, unless they have +correct header values in assembly source. diff --git a/mesonbuild/compilers/asm.py b/mesonbuild/compilers/asm.py index 8cd5e28dc47f..9ae4abe7ab5b 100644 --- a/mesonbuild/compilers/asm.py +++ b/mesonbuild/compilers/asm.py @@ -13,6 +13,7 @@ from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice from ..envconfig import MachineInfo + from ..programs import ExternalProgram nasm_optimization_args: T.Dict[str, T.List[str]] = { 'plain': [], @@ -310,3 +311,44 @@ def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[st def sanity_check(self, work_dir: str, environment: 'Environment') -> None: if self.info.cpu_family not in {'ppc'}: raise EnvironmentException(f'ASM compiler {self.id!r} does not support {self.info.cpu_family} CPU family') + +class RgbdsCompiler(Compiler): + language = 'rgbds' + + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, info: MachineInfo, + linker: DynamicLinker, exe_wrapper: T.Optional['ExternalProgram'] = None, + is_cross: bool = True): + super().__init__([], exelist, version, for_machine, info, linker, is_cross=is_cross) + self.id = 'rgbds' + self.exe_wrapper = exe_wrapper + + def needs_static_linker(self) -> bool: + return True + + def get_optimization_args(self, optimization_level: str) -> T.List[str]: + return [] + + def get_output_args(self, outputname: str) -> T.List[str]: + return ['-o', outputname] + + def get_depfile_suffix(self) -> str: + return 'd' + + def get_include_args(self, path: str, is_system: bool) -> T.List[str]: + if not path: + path = '.' + return ['-I' + path] + + def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: + return ['-M', outfile, '-MQ', outtarget] + + def sanity_check(self, work_dir: str, environment: 'Environment') -> None: + if self.info.cpu_family != 'sm83': + raise EnvironmentException(f'ASM compiler {self.id!r} does not support {self.info.cpu_family} CPU family') + + def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], + build_dir: str) -> T.List[str]: + for idx, i in enumerate(parameter_list): + if i[:2] == '-I': + parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) + return parameter_list diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 603a3eb484de..de8c3a26e4e6 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -69,6 +69,7 @@ 'cython': ('pyx', ), 'nasm': ('asm', 'nasm',), 'masm': ('masm',), + 'rgbds': ('asm',), } all_languages = lang_suffixes.keys() c_cpp_suffixes = {'h'} diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py index 7542fb6283a2..fa0fb33210cf 100644 --- a/mesonbuild/compilers/detect.py +++ b/mesonbuild/compilers/detect.py @@ -79,6 +79,8 @@ defaults['gcc_static_linker'] = ['gcc-ar'] defaults['clang_static_linker'] = ['llvm-ar'] defaults['nasm'] = ['nasm', 'yasm'] +defaults['rgbasm'] = ['rgbasm'] +defaults['rgblink'] = ['rgblink'] def compiler_from_language(env: 'Environment', lang: str, for_machine: MachineChoice) -> T.Optional[Compiler]: @@ -98,6 +100,7 @@ def compiler_from_language(env: 'Environment', lang: str, for_machine: MachineCh 'cython': detect_cython_compiler, 'nasm': detect_nasm_compiler, 'masm': detect_masm_compiler, + 'rgbds': detect_rgbds_compiler, } return lang_map[lang](env, for_machine) if lang in lang_map else None @@ -1353,6 +1356,40 @@ def detect_masm_compiler(env: 'Environment', for_machine: MachineChoice) -> Comp _handle_exceptions(popen_exceptions, [comp]) raise EnvironmentException('Unreachable code (exception to make mypy happy)') +def detect_rgbds_compiler(env: Environment, for_machine: MachineChoice) -> Compiler: + from .asm import RgbdsCompiler + exelist = env.lookup_binary_entry(for_machine, 'rgbasm') + is_cross = env.is_cross_build(for_machine) # true, until Meson is ported to GB + info = env.machines[for_machine] + if exelist is None: + exelist = defaults['rgbasm'] + + try: + output = Popen_safe([exelist[0], '--version'])[1] + except OSError: + raise EnvironmentException('Could not execute RGBDS assembler "{}"'.format(''.join(exelist))) + + version = search_version(output) + linker = _detect_rgblink(env, for_machine) + comp = RgbdsCompiler(exelist, version, for_machine, info, linker, env.exe_wrapper, is_cross) + env.coredata.add_lang_args(comp.language, RgbdsCompiler, for_machine, env) + + return comp + +def _detect_rgblink(env: Environment, for_machine: MachineChoice) -> DynamicLinker: + from ..linkers.linkers import RgbdsLinker + exelist = env.lookup_binary_entry(for_machine, 'rgblink') + if exelist is None: + exelist = defaults['rgblink'] + + try: + output = Popen_safe([exelist[0], '--version'])[1] + except OSError: + raise EnvironmentException('Could not execute RGBDS linker"{}"'.format(''.join(exelist))) + + version = search_version(output) + return RgbdsLinker(exelist, for_machine, '', [], version=version) + # GNU/Clang defines and version # ============================= diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py index 86bad9be23ee..8ad47110f76f 100644 --- a/mesonbuild/envconfig.py +++ b/mesonbuild/envconfig.py @@ -57,6 +57,7 @@ 's390', 's390x', 'sh4', + 'sm83', 'sparc', 'sparc64', 'sw_64', diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index c4df0fa1d893..e537acd85e89 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -1660,3 +1660,16 @@ class MetrowerksLinkerARM(MetrowerksLinker): class MetrowerksLinkerEmbeddedPowerPC(MetrowerksLinker): id = 'mwldeppc' + + +class RgbdsLinker(DynamicLinker): + id = 'rgblink' + + def get_allow_undefined_args(self) -> T.List[str]: + return [] + + def get_output_args(self, outputname: str) -> T.List[str]: + return ['-o', outputname] + + def get_search_args(self, dirname: str) -> T.List[str]: + return [] diff --git a/run_project_tests.py b/run_project_tests.py index ab34c27f21d2..0d1b93072b3b 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -79,7 +79,7 @@ class ArgumentType(CompilerArgumentType): 'keyval', 'platform-osx', 'platform-windows', 'platform-linux', 'java', 'C#', 'vala', 'cython', 'rust', 'd', 'objective c', 'objective c++', 'fortran', 'swift', 'cuda', 'python3', 'python', 'fpga', 'frameworks', 'nasm', 'wasm', 'wayland', - 'format', + 'format', 'rgbds' ] @@ -1136,6 +1136,7 @@ def __init__(self, category: str, subdir: str, skip: bool = False, stdout_mandat TestCategory('wasm', 'wasm', shutil.which('emcc') is None or backend is not Backend.ninja), TestCategory('wayland', 'wayland', should_skip_wayland()), TestCategory('format', 'format'), + TestCategory('rgbds', 'rgbds', shutil.which('rgbasm') is None) ] categories = [t.category for t in all_tests] diff --git a/test cases/rgbds/1 basic/crossfile.ini b/test cases/rgbds/1 basic/crossfile.ini new file mode 100644 index 000000000000..95da9c88f220 --- /dev/null +++ b/test cases/rgbds/1 basic/crossfile.ini @@ -0,0 +1,9 @@ +[binaries] +c = 'gcc' +strip = 'false' + +[host_machine] +system = 'dmg' +cpu_family = 'sm83' +cpu = 'sm8320' +endian = 'little' diff --git a/test cases/rgbds/1 basic/include/hardware.inc b/test cases/rgbds/1 basic/include/hardware.inc new file mode 100644 index 000000000000..ac8703c27bff --- /dev/null +++ b/test cases/rgbds/1 basic/include/hardware.inc @@ -0,0 +1,106 @@ +;* +;* Game Boy Hardware definitions +;* https://github.com/gbdev/hardware.inc +;* +;* Based on Jones' hardware.inc +;* And based on Carsten Sorensen's ideas. +;* +;* To the extent possible under law, the authors of this work have +;* waived all copyright and related or neighboring rights to the work. +;* See https://creativecommons.org/publicdomain/zero/1.0/ for details. +;* +;* SPDX-License-Identifier: CC0-1.0 +;* +;* Trimmed version for unit tests + +; -- +; -- BGP ($FF47) +; -- BG Palette Data (W) +; -- +; -- Bit 7-6 - Intensity for %11 +; -- Bit 5-4 - Intensity for %10 +; -- Bit 3-2 - Intensity for %01 +; -- Bit 1-0 - Intensity for %00 +; -- +DEF rBGP EQU $FF47 + + +;*************************************************************************** +;* +;* Header +;* +;*************************************************************************** + +;* +;* Nintendo scrolling logo +;* (Code won't work on a real Game Boy) +;* (if next lines are altered.) +MACRO NINTENDO_LOGO + DB $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D + DB $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99 + DB $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E +ENDM + +; $0143 Color Game Boy compatibility code +DEF CART_COMPATIBLE_DMG EQU $00 +DEF CART_COMPATIBLE_DMG_GBC EQU $80 +DEF CART_COMPATIBLE_GBC EQU $C0 + +; $0146 Game Boy/Super Game Boy indicator +DEF CART_INDICATOR_GB EQU $00 +DEF CART_INDICATOR_SGB EQU $03 + +; $0147 Cartridge type +DEF CART_ROM EQU $00 +DEF CART_ROM_MBC1 EQU $01 +DEF CART_ROM_MBC1_RAM EQU $02 +DEF CART_ROM_MBC1_RAM_BAT EQU $03 +DEF CART_ROM_MBC2 EQU $05 +DEF CART_ROM_MBC2_BAT EQU $06 +DEF CART_ROM_RAM EQU $08 +DEF CART_ROM_RAM_BAT EQU $09 +DEF CART_ROM_MMM01 EQU $0B +DEF CART_ROM_MMM01_RAM EQU $0C +DEF CART_ROM_MMM01_RAM_BAT EQU $0D +DEF CART_ROM_MBC3_BAT_RTC EQU $0F +DEF CART_ROM_MBC3_RAM_BAT_RTC EQU $10 +DEF CART_ROM_MBC3 EQU $11 +DEF CART_ROM_MBC3_RAM EQU $12 +DEF CART_ROM_MBC3_RAM_BAT EQU $13 +DEF CART_ROM_MBC5 EQU $19 +DEF CART_ROM_MBC5_RAM EQU $1A +DEF CART_ROM_MBC5_RAM_BAT EQU $1B +DEF CART_ROM_MBC5_RUMBLE EQU $1C +DEF CART_ROM_MBC5_RAM_RUMBLE EQU $1D +DEF CART_ROM_MBC5_RAM_BAT_RUMBLE EQU $1E +DEF CART_ROM_MBC7_RAM_BAT_GYRO EQU $22 +DEF CART_ROM_POCKET_CAMERA EQU $FC +DEF CART_ROM_BANDAI_TAMA5 EQU $FD +DEF CART_ROM_HUDSON_HUC3 EQU $FE +DEF CART_ROM_HUDSON_HUC1 EQU $FF + +; $0148 ROM size +; these are kilobytes +DEF CART_ROM_32KB EQU $00 ; 2 banks +DEF CART_ROM_64KB EQU $01 ; 4 banks +DEF CART_ROM_128KB EQU $02 ; 8 banks +DEF CART_ROM_256KB EQU $03 ; 16 banks +DEF CART_ROM_512KB EQU $04 ; 32 banks +DEF CART_ROM_1024KB EQU $05 ; 64 banks +DEF CART_ROM_2048KB EQU $06 ; 128 banks +DEF CART_ROM_4096KB EQU $07 ; 256 banks +DEF CART_ROM_8192KB EQU $08 ; 512 banks +DEF CART_ROM_1152KB EQU $52 ; 72 banks +DEF CART_ROM_1280KB EQU $53 ; 80 banks +DEF CART_ROM_1536KB EQU $54 ; 96 banks + +; $0149 SRAM size +; these are kilobytes +DEF CART_SRAM_NONE EQU 0 +DEF CART_SRAM_8KB EQU 2 ; 1 bank +DEF CART_SRAM_32KB EQU 3 ; 4 banks +DEF CART_SRAM_128KB EQU 4 ; 16 banks + +; $014A Destination code +DEF CART_DEST_JAPANESE EQU $00 +DEF CART_DEST_NON_JAPANESE EQU $01 diff --git a/test cases/rgbds/1 basic/meson.build b/test cases/rgbds/1 basic/meson.build new file mode 100644 index 000000000000..e23b303b49ab --- /dev/null +++ b/test cases/rgbds/1 basic/meson.build @@ -0,0 +1,5 @@ +project('rgbds-test', 'rgbds') + +executable('rgbdstest.gb', 'src/main.asm', + include_directories: ['include'], + link_language: 'rgbds') diff --git a/test cases/rgbds/1 basic/src/main.asm b/test cases/rgbds/1 basic/src/main.asm new file mode 100644 index 000000000000..6ef7e435b888 --- /dev/null +++ b/test cases/rgbds/1 basic/src/main.asm @@ -0,0 +1,33 @@ +INCLUDE "hardware.inc" + +SECTION "start",ROM0[$0100] + nop + jp begin + + NINTENDO_LOGO + + db "EXAMPLE",0,0,0,0,0,0,0,0 ; Cart Name + db CART_COMPATIBLE_DMG + db 0,0 ; Licensee code + db CART_INDICATOR_GB + db CART_ROM + db CART_ROM_32KB + db CART_SRAM_NONE + db CART_DEST_NON_JAPANESE + db $33 ; Old licensee code + db 0 ; Mask ROM version + db $a7 ; Header checksum + dw $5721 ; Global checksum + +begin: + di + ld sp,$ffff + +init: + ld a, %11111100 + ld [rBGP], a ; clear the screen + +wait: + halt + nop + jr wait diff --git a/test cases/rgbds/2 rgbfix/crossfile.ini b/test cases/rgbds/2 rgbfix/crossfile.ini new file mode 100644 index 000000000000..95da9c88f220 --- /dev/null +++ b/test cases/rgbds/2 rgbfix/crossfile.ini @@ -0,0 +1,9 @@ +[binaries] +c = 'gcc' +strip = 'false' + +[host_machine] +system = 'dmg' +cpu_family = 'sm83' +cpu = 'sm8320' +endian = 'little' diff --git a/test cases/rgbds/2 rgbfix/include/hardware.inc b/test cases/rgbds/2 rgbfix/include/hardware.inc new file mode 100644 index 000000000000..ac8703c27bff --- /dev/null +++ b/test cases/rgbds/2 rgbfix/include/hardware.inc @@ -0,0 +1,106 @@ +;* +;* Game Boy Hardware definitions +;* https://github.com/gbdev/hardware.inc +;* +;* Based on Jones' hardware.inc +;* And based on Carsten Sorensen's ideas. +;* +;* To the extent possible under law, the authors of this work have +;* waived all copyright and related or neighboring rights to the work. +;* See https://creativecommons.org/publicdomain/zero/1.0/ for details. +;* +;* SPDX-License-Identifier: CC0-1.0 +;* +;* Trimmed version for unit tests + +; -- +; -- BGP ($FF47) +; -- BG Palette Data (W) +; -- +; -- Bit 7-6 - Intensity for %11 +; -- Bit 5-4 - Intensity for %10 +; -- Bit 3-2 - Intensity for %01 +; -- Bit 1-0 - Intensity for %00 +; -- +DEF rBGP EQU $FF47 + + +;*************************************************************************** +;* +;* Header +;* +;*************************************************************************** + +;* +;* Nintendo scrolling logo +;* (Code won't work on a real Game Boy) +;* (if next lines are altered.) +MACRO NINTENDO_LOGO + DB $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D + DB $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99 + DB $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E +ENDM + +; $0143 Color Game Boy compatibility code +DEF CART_COMPATIBLE_DMG EQU $00 +DEF CART_COMPATIBLE_DMG_GBC EQU $80 +DEF CART_COMPATIBLE_GBC EQU $C0 + +; $0146 Game Boy/Super Game Boy indicator +DEF CART_INDICATOR_GB EQU $00 +DEF CART_INDICATOR_SGB EQU $03 + +; $0147 Cartridge type +DEF CART_ROM EQU $00 +DEF CART_ROM_MBC1 EQU $01 +DEF CART_ROM_MBC1_RAM EQU $02 +DEF CART_ROM_MBC1_RAM_BAT EQU $03 +DEF CART_ROM_MBC2 EQU $05 +DEF CART_ROM_MBC2_BAT EQU $06 +DEF CART_ROM_RAM EQU $08 +DEF CART_ROM_RAM_BAT EQU $09 +DEF CART_ROM_MMM01 EQU $0B +DEF CART_ROM_MMM01_RAM EQU $0C +DEF CART_ROM_MMM01_RAM_BAT EQU $0D +DEF CART_ROM_MBC3_BAT_RTC EQU $0F +DEF CART_ROM_MBC3_RAM_BAT_RTC EQU $10 +DEF CART_ROM_MBC3 EQU $11 +DEF CART_ROM_MBC3_RAM EQU $12 +DEF CART_ROM_MBC3_RAM_BAT EQU $13 +DEF CART_ROM_MBC5 EQU $19 +DEF CART_ROM_MBC5_RAM EQU $1A +DEF CART_ROM_MBC5_RAM_BAT EQU $1B +DEF CART_ROM_MBC5_RUMBLE EQU $1C +DEF CART_ROM_MBC5_RAM_RUMBLE EQU $1D +DEF CART_ROM_MBC5_RAM_BAT_RUMBLE EQU $1E +DEF CART_ROM_MBC7_RAM_BAT_GYRO EQU $22 +DEF CART_ROM_POCKET_CAMERA EQU $FC +DEF CART_ROM_BANDAI_TAMA5 EQU $FD +DEF CART_ROM_HUDSON_HUC3 EQU $FE +DEF CART_ROM_HUDSON_HUC1 EQU $FF + +; $0148 ROM size +; these are kilobytes +DEF CART_ROM_32KB EQU $00 ; 2 banks +DEF CART_ROM_64KB EQU $01 ; 4 banks +DEF CART_ROM_128KB EQU $02 ; 8 banks +DEF CART_ROM_256KB EQU $03 ; 16 banks +DEF CART_ROM_512KB EQU $04 ; 32 banks +DEF CART_ROM_1024KB EQU $05 ; 64 banks +DEF CART_ROM_2048KB EQU $06 ; 128 banks +DEF CART_ROM_4096KB EQU $07 ; 256 banks +DEF CART_ROM_8192KB EQU $08 ; 512 banks +DEF CART_ROM_1152KB EQU $52 ; 72 banks +DEF CART_ROM_1280KB EQU $53 ; 80 banks +DEF CART_ROM_1536KB EQU $54 ; 96 banks + +; $0149 SRAM size +; these are kilobytes +DEF CART_SRAM_NONE EQU 0 +DEF CART_SRAM_8KB EQU 2 ; 1 bank +DEF CART_SRAM_32KB EQU 3 ; 4 banks +DEF CART_SRAM_128KB EQU 4 ; 16 banks + +; $014A Destination code +DEF CART_DEST_JAPANESE EQU $00 +DEF CART_DEST_NON_JAPANESE EQU $01 diff --git a/test cases/rgbds/2 rgbfix/meson.build b/test cases/rgbds/2 rgbfix/meson.build new file mode 100644 index 000000000000..f7a3a68310d6 --- /dev/null +++ b/test cases/rgbds/2 rgbfix/meson.build @@ -0,0 +1,23 @@ +project('rgbds-test', 'rgbds') + +rgbfix = find_program('rgbfix', required: true) + +rom = executable('rgbdstest', 'src/main.asm', + include_directories: ['include'], + link_language: 'rgbds') + +custom_target(output: 'rgbdstest.gb', + input: rom, + command: [ + rgbfix, + '--title', 'EXAMPLE', + '--old-licensee', '0x33', + '--mbc-type', 'ROM', + '--rom-version', '0', + '--non-japanese', + '--validate', + '-', + ], + build_by_default: true, + capture: true, + feed: true) diff --git a/test cases/rgbds/2 rgbfix/src/main.asm b/test cases/rgbds/2 rgbfix/src/main.asm new file mode 100644 index 000000000000..0f548d2104f8 --- /dev/null +++ b/test cases/rgbds/2 rgbfix/src/main.asm @@ -0,0 +1,21 @@ +INCLUDE "hardware.inc" + +SECTION "start",ROM0[$0100] + nop + jp begin + + ;; leave space for rgbfix to add the ROM header. + ds $150 - $104 + +begin: + di + ld sp,$ffff + +init: + ld a, %11111100 + ld [rBGP], a ; clear the screen + +wait: + halt + nop + jr wait