Skip to content

Commit

Permalink
WIP.
Browse files Browse the repository at this point in the history
  • Loading branch information
Arignir committed Dec 18, 2023
1 parent 485775a commit f1dc9ae
Show file tree
Hide file tree
Showing 14 changed files with 302 additions and 8 deletions.
70 changes: 70 additions & 0 deletions .github/workflows/accuracy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Accuracy

on: [push, pull_request, workflow_dispatch]

jobs:
linux:
runs-on: ubuntu-latest
steps:
- name: Fetch Source Code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install -y meson ninja-build libsdl2-dev libglew-dev libgtk-3-dev libreadline-dev libedit-dev libcapstone-dev
- name: Build Hades w/ Debugger
run: |
meson build --werror -Dwith_debugger=true
cd build
ninja
- name: Download Test Roms
run: |
# Download BIOS
echo "$BIOS_DATA" | base64 -d | gpg --pinentry-mode loopback --passphrase "$BIOS_KEY" -d -o ./bios.bin
# Create ROMs directory
mkdir roms
cd roms
# Download AGS
declare ags_url="$(echo "$AGS_URL" | base64 -d | gpg --pinentry-mode loopback --passphrase "$AGS_KEY" -d)"
wget "$ags_url" -O ags.zip
unzip ags.zip
shred -u ags.zip
mv AGB_*.gba ags.gba
# Download the remaining testing ROMs
wget https://raw.githubusercontent.com/jsmolka/gba-tests/master/arm/arm.gba
wget https://raw.githubusercontent.com/jsmolka/gba-tests/master/thumb/thumb.gba
wget https://raw.githubusercontent.com/Arignir/Hades-Tests/master/roms/dma-start-delay.gba
wget https://raw.githubusercontent.com/Arignir/Hades-Tests/master/roms/openbus-bios.gba
wget https://raw.githubusercontent.com/Arignir/Hades-Tests/master/roms/timer-basic.gba
env:
BIOS_DATA: ${{ secrets.BIOS_DATA }}
BIOS_KEY: ${{ secrets.BIOS_KEY }}
AGS_URL: ${{ secrets.AGS_URL }}
AGS_KEY: ${{ secrets.AGS_KEY }}
- name: Check Accuracy
run: |
python3 ./accuracy/check.py --binary ./build/hades --roms ./roms/ -v
- name: Collect Screenshots
uses: actions/upload-artifact@v3
if: always()
with:
name: tests-screenshots
path: './.tests_screenshots/'
if-no-files-found: error
- name: Cleanup
if: always()
run: |
if [[ -f ./bios.bin ]]; then
shred -u ./bios.bin
echo "BIOS deleted"
fi
if [[ -f ./roms/ags.gba ]]; then
shred -u ./roms/ags.gba
echo "AGS deleted"
fi
12 changes: 6 additions & 6 deletions .github/workflows/main.yml → .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ jobs:
run:
shell: msys2 {0}
steps:
- name: 'Sync source code'
- name: Fetch Source Code
uses: actions/checkout@v4
with:
submodules: 'recursive'
submodules: recursive
- name: Install Dependencies
uses: msys2/setup-msys2@v2
with:
Expand All @@ -35,10 +35,10 @@ jobs:
mac-os:
runs-on: macos-latest
steps:
- name: 'Sync source code'
- name: Fetch Source Code
uses: actions/checkout@v4
with:
submodules: 'recursive'
submodules: recursive
- name: Install Dependencies
run: |
brew install meson ninja sdl2 glew create-dmg
Expand Down Expand Up @@ -130,10 +130,10 @@ jobs:
linux:
runs-on: ubuntu-latest
steps:
- name: 'Sync source code'
- name: Fetch Source Code
uses: actions/checkout@v4
with:
submodules: 'recursive'
submodules: recursive
- name: Install Dependencies
run: |
sudo apt-get update
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/screenshots
/build
/build.*
/build-*
/games
/demos
*.gba
*.bin
config.json
.hades-dbg.history
__pycache__

Empty file added accuracy/__init__.py
Empty file.
150 changes: 150 additions & 0 deletions accuracy/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#!/usr/bin/env python3

import os
import shutil
import filecmp
import textwrap
import argparse
import subprocess
import tempfile
from enum import Enum
from pathlib import Path


GREEN = '\033[32m'
YELLOW = '\033[33m'
RED = '\033[31m'
BOLD = '\033[1m'
RESET = '\033[0m'


class TestResult(Enum):
PASS = 0
SKIP = 1
FAIL = 2


class Test():
def __init__(self, name: str, rom: str, code: str, screenshot: str, skip: bool = False):
self.name = name

self.rom = rom
self.code = textwrap.dedent(code)
self.screenshot = screenshot
self.skip = skip

def run(self, hades_path: Path, rom_directory: Path, config_path: Path, tests_screenshots_directory: Path, verbose: bool):
module_path = Path(os.path.realpath(__file__)).parent

subprocess.run(
[hades_path, rom_directory / self.rom, '--without-gui', '--config', config_path],
input=self.code,
stdout=None if verbose else subprocess.DEVNULL,
stderr=None if verbose else subprocess.DEVNULL,
text=True,
encoding='utf-8',
check=True,
)

if not filecmp.cmp(tests_screenshots_directory / self.screenshot, module_path / 'expected' / self.screenshot, shallow=False):
raise RuntimeError("The screenshot taken during the test doesn't match the expected one.")


def main():
from suite import TESTS_SUITE

exit_code = 0

parser = argparse.ArgumentParser(
prog='Hades Accuracy Checker',
description='Tests the accuracy of Hades, a Gameboy Advance Emulator',
)

parser.add_argument(
'--binary',
nargs='?',
default='./hades',
help="Path to Hades' binary",
)

parser.add_argument(
'--roms',
nargs='?',
default='./roms',
help="Path to the test ROMS folder",
)

parser.add_argument(
'--verbose',
'-v',
action='store_true',
help="Show subcommands output",
)

args = parser.parse_args()

hades_binary = Path(os.getcwd()) / args.binary
rom_directory = Path(os.getcwd()) / args.roms

config = tempfile.NamedTemporaryFile()
config.write(textwrap.dedent('''
{
"file": {
"bios": "./bios.bin"
},
"emulation": {
"skip_bios": true,
"speed": 0,
"unbounded": false,
"backup_storage": {
"autodetect": true,
"type": 0
},
"rtc": {
"autodetect": true,
"enabled": true
}
}
}
''').encode('utf-8'))
config.flush()

tests_screenshots_directory = Path(os.getcwd()) / '.tests_screenshots'
if tests_screenshots_directory.exists():
shutil.rmtree(tests_screenshots_directory)
os.mkdir(tests_screenshots_directory)

print(f"┏━{'━' * 30}━┳━━━━━━┓")
print(f"┃ {'Name':30s} ┃ Res. ┃")
print(f"┣━{'━' * 30}━╋━━━━━━┫")

for test in TESTS_SUITE:
result = TestResult.FAIL

try:
if test.skip:
result = TestResult.SKIP
continue

test.run(hades_binary, rom_directory, config.name, tests_screenshots_directory, args.verbose)
result = TestResult.PASS
except Exception:
result = TestResult.FAIL
finally:
if result == TestResult.PASS:
pretty_result = f'{BOLD}{GREEN}PASS{RESET}'
elif result == TestResult.SKIP:
pretty_result = f'{BOLD}{YELLOW}SKIP{RESET}'
else:
pretty_result = f'{BOLD}{RED}FAIL{RESET}'
exit_code = 1

print(f"┃ {test.name:30s}{pretty_result} ┃")

print(f"┗━{'━' * 30}━┻━━━━━━┛")

exit(exit_code)


if __name__ == '__main__':
main()
Binary file added accuracy/expected/ags_01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added accuracy/expected/arm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added accuracy/expected/dma_start_delay.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added accuracy/expected/openbus_bios.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added accuracy/expected/thumb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added accuracy/expected/timer_basic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 68 additions & 0 deletions accuracy/suite.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from typing import List
from check import Test

TESTS_SUITE: List[Test] = [

# Jsmolka's arm.gba & thumg.gba
# https://github.com/jsmolka/gba-tests
Test(
name="Jsmolka - Arm.gba",
rom='arm.gba',
code='''
frame 10
screenshot ./.tests_screenshots/arm.png
''',
screenshot='arm.png',
),
Test(
name="Jsmolka - Thumb.gba",
rom='thumb.gba',
code='''
frame 10
screenshot ./.tests_screenshots/thumb.png
''',
screenshot='thumb.png',
),

# Hades Tests
# https://github.com/Arignir/Hades-Tests
Test(
name="Hades Tests - DMA Start Delay",
rom='dma-start-delay.gba',
code='''
frame 20
screenshot ./.tests_screenshots/dma_start_delay.png
''',
screenshot='dma_start_delay.png',
skip=True,
),
Test(
name="Hades Tests - Openbus BIOS",
rom='openbus-bios.gba',
code='''
frame 20
screenshot ./.tests_screenshots/openbus_bios.png
''',
screenshot='openbus_bios.png',
),
Test(
name="Hades Tests - Timer Basic",
rom='timer-basic.gba',
code='''
frame 20
screenshot ./.tests_screenshots/timer_basic.png
''',
screenshot='timer_basic.png',
),

# AGS
Test(
name="AGS - Aging Tests",
rom='ags.gba',
code='''
frame 425
screenshot ./.tests_screenshots/ags_01.png
''',
screenshot='ags_01.png',
)
]
2 changes: 1 addition & 1 deletion source/app/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ app_config_load(

if (mjson_get_number(data, data_len, "$.emulation.speed", &d)) {
app->emulation.speed = (int)d;
app->emulation.speed = max(1, min(app->emulation.speed, 5));
app->emulation.speed = max(0, min(app->emulation.speed, 5));
}

if (mjson_get_bool(data, data_len, "$.emulation.backup_storage.autodetect", &b)) {
Expand Down
3 changes: 2 additions & 1 deletion source/app/dbg/lang/lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,15 @@ debugger_lang_lexe(
while (input[i]) {
switch (input[i]) {
case '.':
case '_':
case 'a' ... 'z':
case 'A' ... 'Z': {
/* Lexe the whole identifier */
struct token *t;
size_t j;

j = 0;
while (isalnum(input[i + j]) || input[i + j] == '.' || input[i + j] == '/') {
while (isalnum(input[i + j]) || input[i + j] == '.' || input[i + j] == '_' || input[i + j] == '/') {
++j;
}

Expand Down

0 comments on commit f1dc9ae

Please sign in to comment.