mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' into qt
This commit is contained in:
commit
51ad9d37e1
|
@ -1,8 +1,8 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
project(mGBA)
|
||||
project(mGBA C)
|
||||
set(BINARY_NAME mgba CACHE INTERNAL "Name of output binaries")
|
||||
set(CMAKE_C_FLAGS_DEBUG "-g -Wall -Wextra -std=gnu99")
|
||||
set(CMAKE_C_FLAGS_RELEASE "-O3 -Wall -Wextra -std=gnu99")
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -Wall -Wextra -std=gnu99")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -Wall -Wextra -std=gnu99")
|
||||
set(USE_CLI_DEBUGGER ON CACHE BOOL "Whether or not to enable the CLI-mode ARM debugger")
|
||||
set(USE_GDB_STUB ON CACHE BOOL "Whether or not to enable the GDB stub ARM debugger")
|
||||
set(USE_FFMPEG ON CACHE BOOL "Whether or not to enable FFmpeg support")
|
||||
|
@ -24,9 +24,14 @@ include_directories(${CMAKE_SOURCE_DIR}/src/arm)
|
|||
include_directories(${CMAKE_SOURCE_DIR}/src/gba)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/src)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Function definitions
|
||||
include(FindPkgConfig)
|
||||
function(find_feature FEATURE_NAME FEATURE_REQUIRES)
|
||||
if (NOT ${FEATURE_NAME})
|
||||
return()
|
||||
endif()
|
||||
foreach(REQUIRE ${FEATURE_REQUIRES})
|
||||
find_package(${REQUIRE} QUIET)
|
||||
pkg_search_module(${REQUIRE} ${REQUIRE})
|
||||
|
@ -35,6 +40,13 @@ function(find_feature FEATURE_NAME FEATURE_REQUIRES)
|
|||
set(${FEATURE_NAME} OFF PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
string(TOUPPER ${REQUIRE} UREQUIRE)
|
||||
set(${UREQUIRE}_CFLAGS_OTHER ${${REQUIRE}_CFLAGS_OTHER} PARENT_SCOPE)
|
||||
set(${UREQUIRE}_FOUND ${${REQUIRE}_FOUND} PARENT_SCOPE)
|
||||
set(${UREQUIRE}_INCLUDE_DIRS ${${REQUIRE}_INCLUDE_DIRS} PARENT_SCOPE)
|
||||
set(${UREQUIRE}_LIBRARIES ${${REQUIRE}_LIBRARIES} PARENT_SCOPE)
|
||||
set(${UREQUIRE}_LIBRARY_DIRS ${${REQUIRE}_LIBRARY_DIRS} PARENT_SCOPE)
|
||||
set(${UREQUIRE}_LDFLAGS_OTHER ${${REQUIRE}_LDFLAGS_OTHER} PARENT_SCOPE)
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
|
@ -98,7 +110,9 @@ if(USE_CLI_DEBUGGER)
|
|||
add_definitions(-DUSE_CLI_DEBUGGER)
|
||||
list(APPEND DEBUGGER_SRC ${CMAKE_SOURCE_DIR}/src/debugger/cli-debugger.c)
|
||||
list(APPEND DEBUGGER_SRC ${CMAKE_SOURCE_DIR}/src/debugger/parser.c)
|
||||
set(DEBUGGER_LIB ${EDIT_LIBRARIES})
|
||||
include_directories(AFTER ${LIBEDIT_INCLUDE_DIRS})
|
||||
link_directories(${LIBEDIT_LIBRARY_DIRS})
|
||||
set(DEBUGGER_LIB ${LIBEDIT_LIBRARIES})
|
||||
else()
|
||||
set(DEBUGGER_LIB "")
|
||||
endif()
|
||||
|
@ -110,24 +124,22 @@ endif()
|
|||
source_group("ARM debugger" FILES ${DEBUGGER_SRC})
|
||||
|
||||
if(USE_FFMPEG)
|
||||
pkg_search_module(LIBAVCODEC libavcodec)
|
||||
pkg_search_module(LIBAVFORMAT libavcodec;libavformat;libavutil)
|
||||
pkg_search_module(LIBAVUTIL libavutil)
|
||||
add_definitions(-DUSE_FFMPEG)
|
||||
include_directories(AFTER ${LIBAVCODEC_INCLUDE_DIRS} ${LIBAVFORMAT_INCLUDE_DIRS} ${LIBAVUTIL_INCLUDE_DIRS})
|
||||
link_directories(${LIBAVCODEC_LIBRARY_DIRS} ${LIBAVFORMAT_LIBRARY_DIRS} ${LIBAVUTIL_LIBRARY_DIRS})
|
||||
list(APPEND UTIL_SRC "${CMAKE_SOURCE_DIR}/src/platform/ffmpeg/ffmpeg-encoder.c")
|
||||
list(APPEND DEPENDENCY_LIB ${LIBAVCODEC_LIBRARIES} ${LIBAVFORMAT_LIBRARIES} ${LIBAVUTIL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(USE_PNG)
|
||||
find_package(PNG)
|
||||
find_package(ZLIB)
|
||||
add_definitions(-DUSE_PNG)
|
||||
include_directories(${PNG_PNG_INCLUDE_DIR})
|
||||
include_directories(AFTER ${PNG_INCLUDE_DIRS})
|
||||
list(APPEND DEPENDENCY_LIB ${PNG_LIBRARIES} ${ZLIB_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(USE_LIBZIP)
|
||||
include_directories(${LIBZIP_INCLUDE_DIRS})
|
||||
include_directories(AFTER ${LIBZIP_INCLUDE_DIRS})
|
||||
link_directories(${LIBZIP_LIBRARY_DIRS})
|
||||
list(APPEND DEPENDENCY_LIB ${LIBZIP_LIBRARIES})
|
||||
add_definitions(-DENABLE_LIBZIP)
|
||||
endif()
|
||||
|
@ -156,6 +168,7 @@ if(BUILD_PERF)
|
|||
add_executable(${BINARY_NAME}-perf ${PERF_SRC})
|
||||
target_link_libraries(${BINARY_NAME}-perf ${BINARY_NAME} ${PERF_LIB})
|
||||
install(TARGETS ${BINARY_NAME}-perf DESTINATION bin)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/tools/perf.py DESTINATION "${CMAKE_INSTALL_LIBDIR}/${BINARY_NAME}")
|
||||
endif()
|
||||
|
||||
# Summaries
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef ARM_H
|
||||
#define ARM_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
enum {
|
||||
ARM_SP = 13,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef ISA_ARM_H
|
||||
#define ISA_ARM_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#define ARM_PREFETCH_CYCLES (1 + cpu->memory.activeSeqCycles32)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef ISA_INLINES_H
|
||||
#define ISA_INLINES_H
|
||||
|
||||
#include "common.h"
|
||||
#include "macros.h"
|
||||
|
||||
#include "arm.h"
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef ISA_THUMB_H
|
||||
#define ISA_THUMB_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
struct ARMCore;
|
||||
|
||||
|
|
|
@ -1,20 +1,7 @@
|
|||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
#ifndef MACROS_H
|
||||
#define MACROS_H
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define UNUSED(V) (void)(V)
|
||||
#include "util/common.h"
|
||||
|
||||
#if defined(__PPC__) || defined(__POWERPC__)
|
||||
#define LOAD_32(DEST, ADDR, ARR) { \
|
|
@ -72,6 +72,9 @@ static struct {
|
|||
{ "disasm", _disassemble, _DVParse, "Disassemble instructions" },
|
||||
{ "disasm/a", _disassembleArm, _DVParse, "Disassemble instructions as ARM" },
|
||||
{ "disasm/t", _disassembleThumb, _DVParse, "Disassemble instructions as Thumb" },
|
||||
{ "disassemble", _disassemble, _DVParse, "Disassemble instructions" },
|
||||
{ "disassemble/a", _disassembleArm, _DVParse, "Disassemble instructions as ARM" },
|
||||
{ "disassemble/t", _disassembleThumb, _DVParse, "Disassemble instructions as Thumb" },
|
||||
{ "h", _printHelp, _DVStringParse, "Print help" },
|
||||
{ "help", _printHelp, _DVStringParse, "Print help" },
|
||||
{ "i", _printStatus, 0, "Print the current status" },
|
||||
|
@ -233,16 +236,17 @@ static void _printHelp(struct CLIDebugger* debugger, struct DebugVector* dv) {
|
|||
static inline void _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
|
||||
char disassembly[48];
|
||||
struct ARMInstructionInfo info;
|
||||
printf("%08X: ", address);
|
||||
if (mode == MODE_ARM) {
|
||||
uint32_t instruction = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0);
|
||||
ARMDecodeARM(instruction, &info);
|
||||
ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly));
|
||||
printf("%08X: %s\n", instruction, disassembly);
|
||||
printf("%08X\t%s\n", instruction, disassembly);
|
||||
} else {
|
||||
uint16_t instruction = debugger->d.cpu->memory.loadU16(debugger->d.cpu, address, 0);
|
||||
ARMDecodeThumb(instruction, &info);
|
||||
ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
|
||||
printf("%04X: %s\n", instruction, disassembly);
|
||||
printf("%04X\t%s\n", instruction, disassembly);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -579,6 +583,10 @@ static void _reportEntry(struct ARMDebugger* debugger, enum DebuggerEntryReason
|
|||
static unsigned char _tabComplete(EditLine* elstate, int ch) {
|
||||
UNUSED(ch);
|
||||
const LineInfo* li = el_line(elstate);
|
||||
if (!li->buffer[0]) {
|
||||
return CC_ERROR;
|
||||
}
|
||||
|
||||
const char* commandPtr;
|
||||
int cmd = 0, len = 0;
|
||||
const char* name = 0;
|
||||
|
@ -593,9 +601,29 @@ static unsigned char _tabComplete(EditLine* elstate, int ch) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (_debuggerCommands[cmd + 1].name && strncasecmp(_debuggerCommands[cmd + 1].name, li->buffer, len - 1) == 0) {
|
||||
if (!name) {
|
||||
return CC_ERROR;
|
||||
}
|
||||
if (_debuggerCommands[cmd + 1].name && name[len - 2] == _debuggerCommands[cmd + 1].name[len - 2]) {
|
||||
--len;
|
||||
const char* next = 0;
|
||||
int i;
|
||||
for (i = cmd + 1; _debuggerCommands[i].name; ++i) {
|
||||
if (strncasecmp(name, _debuggerCommands[i].name, len)) {
|
||||
break;
|
||||
}
|
||||
next = _debuggerCommands[i].name;
|
||||
}
|
||||
|
||||
for (; name[len]; ++len) {
|
||||
if (name[len] != next[len]) {
|
||||
break;
|
||||
}
|
||||
char out[2] = { name[len], '\0' };
|
||||
el_insertstr(elstate, out);
|
||||
}
|
||||
return CC_REDISPLAY;
|
||||
}
|
||||
name += len - 1;
|
||||
el_insertstr(elstate, name);
|
||||
el_insertstr(elstate, " ");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef CLI_DEBUGGER_H
|
||||
#define CLI_DEBUGGER_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include "debugger.h"
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef DEBUGGER_H
|
||||
#define DEBUGGER_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include "arm.h"
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef GDB_STUB_H
|
||||
#define GDB_STUB_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include "debugger/debugger.h"
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef MEMORY_DEBUGGER_H
|
||||
#define MEMORY_DEBUGGER_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include "arm.h"
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) {
|
|||
break;
|
||||
case '0':
|
||||
state = LEX_EXPECT_PREFIX;
|
||||
next = 0;
|
||||
break;
|
||||
case '$':
|
||||
state = LEX_EXPECT_HEX;
|
||||
|
@ -120,6 +121,33 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) {
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case LEX_EXPECT_BINARY:
|
||||
switch (token) {
|
||||
case '0':
|
||||
case '1':
|
||||
// TODO: handle overflow
|
||||
next <<= 1;
|
||||
next += token - '0';
|
||||
break;
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
lv->token.type = TOKEN_UINT_TYPE;
|
||||
lv->token.uintValue = next;
|
||||
lv = _lexOperator(lv, token);
|
||||
state = LEX_ROOT;
|
||||
break;
|
||||
case ')':
|
||||
lv->token.type = TOKEN_UINT_TYPE;
|
||||
lv->token.uintValue = next;
|
||||
state = LEX_EXPECT_OPERATOR;
|
||||
break;
|
||||
default:
|
||||
state = LEX_ERROR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case LEX_EXPECT_DECIMAL:
|
||||
switch (token) {
|
||||
case '0':
|
||||
|
@ -216,8 +244,24 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) {
|
|||
next = 0;
|
||||
state = LEX_EXPECT_HEX;
|
||||
break;
|
||||
default:
|
||||
state = LEX_ERROR;
|
||||
case 'B':
|
||||
case 'b':
|
||||
next = 0;
|
||||
state = LEX_EXPECT_BINARY;
|
||||
break;
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
lv->token.type = TOKEN_UINT_TYPE;
|
||||
lv->token.uintValue = next;
|
||||
lv = _lexOperator(lv, token);
|
||||
state = LEX_ROOT;
|
||||
break;
|
||||
case ')':
|
||||
lv->token.type = TOKEN_UINT_TYPE;
|
||||
lv->token.uintValue = next;
|
||||
state = LEX_EXPECT_OPERATOR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -245,8 +289,10 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) {
|
|||
}
|
||||
|
||||
switch (state) {
|
||||
case LEX_EXPECT_BINARY:
|
||||
case LEX_EXPECT_DECIMAL:
|
||||
case LEX_EXPECT_HEX:
|
||||
case LEX_EXPECT_PREFIX:
|
||||
lv->token.type = TOKEN_UINT_TYPE;
|
||||
lv->token.uintValue = next;
|
||||
break;
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
#ifndef PARSER_H
|
||||
#define PARSER_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
#include "debugger.h"
|
||||
|
||||
enum LexState {
|
||||
LEX_ERROR = -1,
|
||||
LEX_ROOT = 0,
|
||||
LEX_EXPECT_IDENTIFIER,
|
||||
LEX_EXPECT_BINARY,
|
||||
LEX_EXPECT_DECIMAL,
|
||||
LEX_EXPECT_HEX,
|
||||
LEX_EXPECT_PREFIX,
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#ifndef GBA_AUDIO_H
|
||||
#define GBA_AUDIO_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
#include "macros.h"
|
||||
|
||||
#include "util/circle-buffer.h"
|
||||
|
||||
|
|
|
@ -283,6 +283,11 @@ static void _unLz77(struct GBA* gba, uint32_t source, uint8_t* dest) {
|
|||
}
|
||||
}
|
||||
|
||||
DECL_BITFIELD(HuffmanNode, uint8_t);
|
||||
DECL_BITS(HuffmanNode, Offset, 0, 6);
|
||||
DECL_BIT(HuffmanNode, RTerm, 6);
|
||||
DECL_BIT(HuffmanNode, LTerm, 7);
|
||||
|
||||
static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t* dest) {
|
||||
struct ARMCore* cpu = gba->cpu;
|
||||
source = source & 0xFFFFFFFC;
|
||||
|
@ -303,39 +308,32 @@ static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t* dest) {
|
|||
uint32_t sPointer = source + 5 + treesize;
|
||||
uint32_t* dPointer = dest;
|
||||
uint32_t nPointer = treeBase;
|
||||
union HuffmanNode {
|
||||
struct {
|
||||
unsigned offset : 6;
|
||||
unsigned rTerm : 1;
|
||||
unsigned lTerm : 1;
|
||||
};
|
||||
uint8_t packed;
|
||||
} node;
|
||||
HuffmanNode node;
|
||||
int bitsRemaining;
|
||||
int readBits;
|
||||
int bitsSeen = 0;
|
||||
node.packed = cpu->memory.load8(cpu, nPointer, 0);
|
||||
node = cpu->memory.load8(cpu, nPointer, 0);
|
||||
while (remaining > 0) {
|
||||
uint32_t bitstream = cpu->memory.load32(cpu, sPointer, 0);
|
||||
sPointer += 4;
|
||||
for (bitsRemaining = 32; bitsRemaining > 0; --bitsRemaining, bitstream <<= 1) {
|
||||
uint32_t next = (nPointer & ~1) + node.offset * 2 + 2;
|
||||
uint32_t next = (nPointer & ~1) + HuffmanNodeGetOffset(node) * 2 + 2;
|
||||
if (bitstream & 0x80000000) {
|
||||
// Go right
|
||||
if (node.rTerm) {
|
||||
if (HuffmanNodeIsRTerm(node)) {
|
||||
readBits = cpu->memory.load8(cpu, next + 1, 0);
|
||||
} else {
|
||||
nPointer = next + 1;
|
||||
node.packed = cpu->memory.load8(cpu, nPointer, 0);
|
||||
node = cpu->memory.load8(cpu, nPointer, 0);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// Go left
|
||||
if (node.lTerm) {
|
||||
if (HuffmanNodeIsLTerm(node)) {
|
||||
readBits = cpu->memory.load8(cpu, next, 0);
|
||||
} else {
|
||||
nPointer = next;
|
||||
node.packed = cpu->memory.load8(cpu, nPointer, 0);
|
||||
node = cpu->memory.load8(cpu, nPointer, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -343,7 +341,7 @@ static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t* dest) {
|
|||
block |= (readBits & ((1 << bits) - 1)) << bitsSeen;
|
||||
bitsSeen += bits;
|
||||
nPointer = treeBase;
|
||||
node.packed = cpu->memory.load8(cpu, nPointer, 0);
|
||||
node = cpu->memory.load8(cpu, nPointer, 0);
|
||||
if (bitsSeen == 32) {
|
||||
bitsSeen = 0;
|
||||
*dPointer = block;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef GBA_BIOS_H
|
||||
#define GBA_BIOS_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include "arm.h"
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef GBA_GPIO_H
|
||||
#define GBA_GPIO_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#define IS_GPIO_REGISTER(reg) ((reg) == GPIO_REG_DATA || (reg) == GPIO_REG_DIRECTION || (reg) == GPIO_REG_CONTROL)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef GBA_IO_H
|
||||
#define GBA_IO_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include "gba.h"
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "gba-memory.h"
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
#include "gba-gpio.h"
|
||||
#include "gba-io.h"
|
||||
#include "gba-serialize.h"
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#ifndef GBA_MEMORY_H
|
||||
#define GBA_MEMORY_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include "arm.h"
|
||||
#include "macros.h"
|
||||
|
||||
#include "gba-gpio.h"
|
||||
#include "gba-savedata.h"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef GBA_RR_H
|
||||
#define GBA_RR_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
struct GBA;
|
||||
struct VDir;
|
||||
|
|
|
@ -343,7 +343,9 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
|
|||
savedata->currentBank = &savedata->data[bank << 16];
|
||||
if (bank > 0) {
|
||||
savedata->type = SAVEDATA_FLASH1M;
|
||||
savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
|
||||
if (savedata->vf) {
|
||||
savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef GBA_SAVEDATA_H
|
||||
#define GBA_SAVEDATA_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
struct VFile;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef GBA_SENSORS_H
|
||||
#define GBA_SENSORS_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
struct GBARotationSource {
|
||||
void (*sample)(struct GBARotationSource*);
|
||||
|
|
|
@ -103,17 +103,9 @@ void GBADeserialize(struct GBA* gba, struct GBASerializedState* state) {
|
|||
}
|
||||
|
||||
static struct VFile* _getStateVf(struct GBA* gba, struct VDir* dir, int slot, bool write) {
|
||||
char path[PATH_MAX];
|
||||
path[PATH_MAX - 1] = '\0';
|
||||
struct VFile* vf;
|
||||
if (!dir) {
|
||||
snprintf(path, PATH_MAX - 1, "%s.ss%d", gba->activeFile, slot);
|
||||
vf = VFileOpen(path, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY);
|
||||
} else {
|
||||
snprintf(path, PATH_MAX - 1, "savestate.ss%d", slot);
|
||||
vf = dir->openFile(dir, path, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY);
|
||||
}
|
||||
return vf;
|
||||
char suffix[5] = { '\0' };
|
||||
snprintf(suffix, sizeof(suffix), ".ss%d", slot);
|
||||
return VDirOptionalOpenFile(dir, gba->activeFile, "savestate", suffix, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY);
|
||||
}
|
||||
|
||||
#ifdef USE_PNG
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef GBA_SERIALIZE_H
|
||||
#define GBA_SERIALIZE_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include "gba.h"
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef GBA_SIO_H
|
||||
#define GBA_SIO_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
enum GBASIOMode {
|
||||
SIO_NORMAL_8 = 0,
|
||||
|
|
|
@ -276,35 +276,12 @@ bool GBAThreadStart(struct GBAThread* threadContext) {
|
|||
}
|
||||
|
||||
}
|
||||
if (threadContext->stateDir) {
|
||||
threadContext->save = threadContext->stateDir->openFile(threadContext->stateDir, "sram.sav", O_RDWR | O_CREAT);
|
||||
}
|
||||
|
||||
if (!threadContext->rom) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (threadContext->fname && !threadContext->save) {
|
||||
char* savedata = 0;
|
||||
char* dotPoint = strrchr(threadContext->fname, '.');
|
||||
if (dotPoint > strrchr(threadContext->fname, '/') && dotPoint[1] && dotPoint[2] && dotPoint[3]) {
|
||||
savedata = strdup(threadContext->fname);
|
||||
dotPoint = strrchr(savedata, '.');
|
||||
dotPoint[1] = 's';
|
||||
dotPoint[2] = 'a';
|
||||
dotPoint[3] = 'v';
|
||||
dotPoint[4] = '\0';
|
||||
} else if (dotPoint) {
|
||||
savedata = malloc((dotPoint - threadContext->fname + 5) * sizeof(char));
|
||||
strncpy(savedata, threadContext->fname, dotPoint - threadContext->fname + 1);
|
||||
strcat(savedata, "sav");
|
||||
} else {
|
||||
savedata = malloc(strlen(threadContext->fname + 5) * sizeof(char));
|
||||
sprintf(savedata, "%s.sav", threadContext->fname);
|
||||
}
|
||||
threadContext->save = VFileOpen(savedata, O_RDWR | O_CREAT);
|
||||
free(savedata);
|
||||
}
|
||||
threadContext->save = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "sram", ".sav", O_CREAT | O_RDWR);
|
||||
|
||||
MutexInit(&threadContext->stateMutex);
|
||||
ConditionInit(&threadContext->stateCond);
|
||||
|
@ -524,7 +501,7 @@ struct GBAThread* GBAThreadGetContext(void) {
|
|||
void GBAThreadTakeScreenshot(struct GBAThread* threadContext) {
|
||||
unsigned stride;
|
||||
void* pixels = 0;
|
||||
struct VFile* vf = threadContext->stateDir->openFile(threadContext->stateDir, "screenshot.png", O_CREAT | O_WRONLY);
|
||||
struct VFile* vf = VDirOptionalOpenFile(threadContext->stateDir, threadContext->gba->activeFile, "screenshot", ".png", O_CREAT | O_TRUNC | O_WRONLY);
|
||||
threadContext->gba->video.renderer->getPixels(threadContext->gba->video.renderer, &stride, &pixels);
|
||||
png_structp png = PNGWriteOpen(vf);
|
||||
png_infop info = PNGWriteHeader(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef GBA_THREAD_H
|
||||
#define GBA_THREAD_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include "gba.h"
|
||||
#include "gba-input.h"
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#ifndef GBA_VIDEO_H
|
||||
#define GBA_VIDEO_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include "gba-memory.h"
|
||||
#include "macros.h"
|
||||
|
||||
#ifdef COLOR_16_BIT
|
||||
#define BYTES_PER_PIXEL 2
|
||||
|
|
|
@ -554,16 +554,17 @@ static void _GBAVLog(struct GBA* gba, enum GBALogLevel level, const char* format
|
|||
if (!gba) {
|
||||
gba = threadContext->gba;
|
||||
}
|
||||
if (threadContext->logHandler) {
|
||||
threadContext->logHandler(threadContext, level, format, args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (gba && !(level & gba->logLevel) && level != GBA_LOG_FATAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (threadContext && threadContext->logHandler) {
|
||||
threadContext->logHandler(threadContext, level, format, args);
|
||||
return;
|
||||
}
|
||||
|
||||
vprintf(format, args);
|
||||
printf("\n");
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef GBA_H
|
||||
#define GBA_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include "arm.h"
|
||||
#include "debugger/debugger.h"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef HLE_BIOS_H
|
||||
#define HLE_BIOS_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
extern const uint8_t hleBios[];
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef VIDEO_GLSL_H
|
||||
#define VIDEO_GLSL_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include "gba-video.h"
|
||||
|
||||
|
|
|
@ -365,7 +365,7 @@ static void _breakWindow(struct GBAVideoSoftwareRenderer* softwareRenderer, stru
|
|||
softwareRenderer->windows[activeWindow].endX = win->h.end;
|
||||
if (win->h.end >= oldWindow.endX) {
|
||||
// Trim off extra windows we've overwritten
|
||||
for (++activeWindow; win->h.end >= softwareRenderer->windows[activeWindow].endX && softwareRenderer->nWindows > activeWindow; ++activeWindow) {
|
||||
for (++activeWindow; softwareRenderer->nWindows > activeWindow + 1 && win->h.end >= softwareRenderer->windows[activeWindow].endX; ++activeWindow) {
|
||||
softwareRenderer->windows[activeWindow] = softwareRenderer->windows[activeWindow + 1];
|
||||
--softwareRenderer->nWindows;
|
||||
}
|
||||
|
@ -1193,6 +1193,9 @@ static void _drawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, stru
|
|||
int flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND;
|
||||
flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA);
|
||||
flags |= FLAG_TARGET_2 * background->target2;
|
||||
if (renderer->blda == 0x10 && renderer->bldb == 0) {
|
||||
flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2);
|
||||
}
|
||||
|
||||
uint32_t screenBase;
|
||||
uint32_t charBase;
|
||||
|
@ -1255,6 +1258,9 @@ static void _drawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, stru
|
|||
int flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; \
|
||||
flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA); \
|
||||
flags |= FLAG_TARGET_2 * background->target2; \
|
||||
if (renderer->blda == 0x10 && renderer->bldb == 0) { \
|
||||
flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \
|
||||
} \
|
||||
int variant = background->target1 && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN); \
|
||||
color_t* palette = renderer->normalPalette; \
|
||||
if (variant) { \
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef VIDEO_SOFTWARE_H
|
||||
#define VIDEO_SOFTWARE_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include "gba-video.h"
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef COMMAND_LINE_H
|
||||
#define COMMAND_LINE_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
enum DebuggerType {
|
||||
DEBUGGER_NONE = 0,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define PERF_OPTIONS "F:NPS:"
|
||||
|
@ -96,9 +97,9 @@ int main(int argc, char** argv) {
|
|||
} else {
|
||||
rendererName = "software";
|
||||
}
|
||||
printf("%s,%i,%lli,%s\n", gameCode, frames, duration, rendererName);
|
||||
printf("%s,%i,%" PRIu64 ",%s\n", gameCode, frames, duration, rendererName);
|
||||
} else {
|
||||
printf("%u frames in %lli microseconds: %g fps (%gx)\n", frames, duration, scaledFrames / duration, scaledFrames / (duration * 60.f));
|
||||
printf("%u frames in %" PRIu64 " microseconds: %g fps (%gx)\n", frames, duration, scaledFrames / duration, scaledFrames / (duration * 60.f));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -148,6 +149,7 @@ static void _GBAPerfShutdown(int signal) {
|
|||
|
||||
static bool _parsePerfOpts(struct SubParser* parser, int option, const char* arg) {
|
||||
struct PerfOpts* opts = parser->opts;
|
||||
errno = 0;
|
||||
switch (option) {
|
||||
case 'F':
|
||||
opts->frames = strtoul(arg, 0, 10);
|
||||
|
|
|
@ -14,10 +14,11 @@ endif()
|
|||
|
||||
if(SDL_VERSION EQUAL "1.2" OR NOT SDL2_FOUND)
|
||||
find_package(SDL 1.2)
|
||||
set(SDL_VERSION "1.2" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if (NOT SDL2_FOUND AND NOT SDL_FOUND)
|
||||
set(BUILD_SDL OFF)
|
||||
set(BUILD_SDL OFF PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef SDL_AUDIO_H
|
||||
#define SDL_AUDIO_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef SDL_EVENTS_H
|
||||
#define SDL_EVENTS_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#include "gba-thread.h"
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef CIRCLE_BUFFER_H
|
||||
#define CIRCLE_BUFFER_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
struct CircleBuffer {
|
||||
void* data;
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define UNUSED(V) (void)(V)
|
||||
|
||||
#endif
|
|
@ -1,8 +1,7 @@
|
|||
#ifndef CRC32_H
|
||||
#define CRC32_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "util/common.h"
|
||||
|
||||
struct VFile;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
void* anonymousMemoryMap(size_t size);
|
||||
void mappedMemoryFree(void* memory, size_t size);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef PATCH_IPS_H
|
||||
#define PATCH_IPS_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
struct Patch;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef PATCH_UPS_H
|
||||
#define PATCH_UPS_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
struct Patch;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef PATCH_H
|
||||
#define PATCH_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
struct VFile;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef PNG_IO_H
|
||||
#define PNG_IO_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#ifdef USE_PNG
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef SOCKET_H
|
||||
#define SOCKET_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define restrict __restrict__
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef THREADING_H
|
||||
#define THREADING_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
#ifdef USE_PTHREADS
|
||||
#include <pthread.h>
|
||||
|
|
|
@ -183,6 +183,34 @@ struct VDir* VDirOpen(const char* path) {
|
|||
return &vd->d;
|
||||
}
|
||||
|
||||
struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const char* prefix, const char* suffix, int mode) {
|
||||
char path[PATH_MAX];
|
||||
path[PATH_MAX - 1] = '\0';
|
||||
struct VFile* vf;
|
||||
if (!dir) {
|
||||
if (!realPath) {
|
||||
return 0;
|
||||
}
|
||||
char* dotPoint = strrchr(realPath, '.');
|
||||
if (dotPoint - realPath + 1 >= PATH_MAX - 1) {
|
||||
return 0;
|
||||
}
|
||||
if (dotPoint > strrchr(realPath, '/')) {
|
||||
int len = dotPoint - realPath;
|
||||
strncpy(path, realPath, len);
|
||||
path[len] = 0;
|
||||
strncat(path + len, suffix, PATH_MAX - len - 1);
|
||||
} else {
|
||||
snprintf(path, PATH_MAX - 1, "%s%s", realPath, suffix);
|
||||
}
|
||||
vf = VFileOpen(path, mode);
|
||||
} else {
|
||||
snprintf(path, PATH_MAX - 1, "%s%s", prefix, suffix);
|
||||
vf = dir->openFile(dir, path, mode);
|
||||
}
|
||||
return vf;
|
||||
}
|
||||
|
||||
bool _vdClose(struct VDir* vd) {
|
||||
struct VDirDE* vdde = (struct VDirDE*) vd;
|
||||
if (closedir(vdde->de) < 0) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef VFS_H
|
||||
#define VFS_H
|
||||
|
||||
#include "common.h"
|
||||
#include "util/common.h"
|
||||
|
||||
enum {
|
||||
MAP_READ = 1,
|
||||
|
@ -39,4 +39,6 @@ struct VDir* VDirOpen(const char* path);
|
|||
struct VDir* VDirOpenZip(const char* path, int flags);
|
||||
#endif
|
||||
|
||||
struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const char* prefix, const char* suffix, int mode);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
#!/usr/bin/env python
|
||||
from __future__ import print_function
|
||||
import argparse
|
||||
import csv
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
class PerfTest(object):
|
||||
EXECUTABLE = 'mgba-perf'
|
||||
|
||||
def __init__(self, rom, renderer='software'):
|
||||
self.rom = rom
|
||||
self.renderer = renderer
|
||||
self.results = None
|
||||
self.name = 'Perf Test: {}'.format(rom)
|
||||
|
||||
def get_args(self):
|
||||
return []
|
||||
|
||||
def wait(self, proc):
|
||||
pass
|
||||
|
||||
def run(self, cwd):
|
||||
args = [os.path.join(os.getcwd(), self.EXECUTABLE), '-P']
|
||||
args.extend(self.get_args())
|
||||
if self.renderer != 'software':
|
||||
args.append('-N')
|
||||
args.append(self.rom)
|
||||
env = {}
|
||||
if 'LD_LIBRARY_PATH' in os.environ:
|
||||
env['LD_LIBRARY_PATH'] = os.path.abspath(os.environ['LD_LIBRARY_PATH'])
|
||||
env['DYLD_LIBRARY_PATH'] = env['LD_LIBRARY_PATH'] # Fake it on OS X
|
||||
proc = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd, universal_newlines=True, env=env)
|
||||
try:
|
||||
self.wait(proc)
|
||||
proc.wait()
|
||||
except:
|
||||
proc.kill()
|
||||
raise
|
||||
if proc.returncode < 0:
|
||||
print('Game crashed!', file=sys.stderr)
|
||||
return
|
||||
reader = csv.DictReader(proc.stdout)
|
||||
self.results = next(reader)
|
||||
|
||||
class WallClockTest(PerfTest):
|
||||
def __init__(self, rom, duration, renderer='software'):
|
||||
super(WallClockTest, self).__init__(rom, renderer)
|
||||
self.duration = duration
|
||||
self.name = 'Wall-Clock Test ({} seconds, {} renderer): {}'.format(duration, renderer, rom)
|
||||
|
||||
def wait(self, proc):
|
||||
time.sleep(self.duration)
|
||||
proc.send_signal(signal.SIGINT)
|
||||
|
||||
class GameClockTest(PerfTest):
|
||||
def __init__(self, rom, frames, renderer='software'):
|
||||
super(GameClockTest, self).__init__(rom, renderer)
|
||||
self.frames = frames
|
||||
self.name = 'Game-Clock Test ({} frames, {} renderer): {}'.format(frames, renderer, rom)
|
||||
|
||||
def get_args(self):
|
||||
return ['-F', str(self.frames)]
|
||||
|
||||
class Suite(object):
|
||||
def __init__(self, cwd, wall=None, game=None, renderer='software'):
|
||||
self.cwd = cwd
|
||||
self.tests = []
|
||||
self.wall = wall
|
||||
self.game = game
|
||||
self.renderer = renderer
|
||||
|
||||
def collect_tests(self):
|
||||
roms = []
|
||||
for f in os.listdir(self.cwd):
|
||||
if f.endswith('.gba'):
|
||||
roms.append(f)
|
||||
roms.sort()
|
||||
for rom in roms:
|
||||
self.add_tests(rom)
|
||||
|
||||
def add_tests(self, rom):
|
||||
if self.wall:
|
||||
self.tests.append(WallClockTest(rom, self.wall, renderer=self.renderer))
|
||||
if self.game:
|
||||
self.tests.append(GameClockTest(rom, self.game, renderer=self.renderer))
|
||||
|
||||
def run(self):
|
||||
results = []
|
||||
for test in self.tests:
|
||||
print('Running test {}'.format(test.name), file=sys.stderr)
|
||||
try:
|
||||
test.run(self.cwd)
|
||||
except KeyboardInterrupt:
|
||||
print('Interrupted, returning early...', file=sys.stderr)
|
||||
return results
|
||||
if test.results:
|
||||
results.append(test.results)
|
||||
return results
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-w', '--wall-time', type=float, default=0, metavar='TIME', help='wall-clock time')
|
||||
parser.add_argument('-g', '--game-frames', type=int, default=0, metavar='FRAMES', help='game-clock frames')
|
||||
parser.add_argument('-N', '--disable-renderer', action='store_const', const=True, help='disable video rendering')
|
||||
parser.add_argument('-o', '--out', metavar='FILE', help='output file path')
|
||||
parser.add_argument('directory', help='directory containing ROM files')
|
||||
args = parser.parse_args()
|
||||
|
||||
s = Suite(args.directory, wall=args.wall_time, game=args.game_frames, renderer=None if args.disable_renderer else 'software')
|
||||
s.collect_tests()
|
||||
results = s.run()
|
||||
fout = sys.stdout
|
||||
if args.out:
|
||||
fout = open(args.out, 'w')
|
||||
writer = csv.DictWriter(fout, results[0].keys())
|
||||
writer.writeheader()
|
||||
writer.writerows(results)
|
||||
if fout is not sys.stdout:
|
||||
fout.close()
|
Loading…
Reference in New Issue