Update to bsnes v028 release.

Changelog:
    - OpenGL (with hardware filter mode support) and SDL video drivers added to Linux port
    - OpenAL (with speed regulation disable support) and OSS audio drivers added to Linux port [Nach]
    - SDL input driver (with joypad support) added to Linux port
    - Emulator pause option added
    - Added option to select behavior of bsnes when idle: allow input, ignore input or pause emulator
    - Added support to remap common GUI actions to key/joypad presses on the "Input Configuration" screen
    - bsnes will now clamp the video output size when it is larger than the screen resolution
    - GUI library has been enhanced, and renamed to hiro
    - Fullscreen mode now always centers video, rather than approximates
    - Fullscreen mode now works correctly on Linux/Openbox
    - Extra layer of abstraction in src/ui has been removed, as GUI lib unifies all ports anyway
    - Video, audio and input drivers unified into standard library, named ruby
    - All custom headers have been merged into a new template library, named nall
    - Makefile rewritten, vastly improved. Allows quick toggling of compiled-in drivers
    - Makefile: all object files now placed in /src/obj, binary placed in /
    - libco greatly enhanced, no longer requires an assembler to build [byuu, blargg, Nach]
    - libco SJLJ driver added; bsnes should now build on any Unix-derivative now (Solaris, OS X, PS3, etc) [Nach]
    - Fixed register $213e.d4 PPU1 open bus behavior [zones]
    - Windows port will not activate screensaver while bsnes is running [Nightcrawler]
    - Visual C++ target no longer requires stdint.h
    - And lots more -- mostly code refactoring related
This commit is contained in:
byuu 2008-02-04 16:16:34 +00:00
parent b934ce41d9
commit dc692754c3
11 changed files with 411 additions and 447 deletions

51
fiber.c Normal file
View File

@ -0,0 +1,51 @@
/*
libco.win (2008-01-28)
authors: Nach, byuu
license: public domain
*/
#define LIBCO_C
#include "../libco.h"
#define WINVER 0x0400
#define _WIN32_WINNT 0x0400
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
static thread_local cothread_t co_active_ = 0;
static void __stdcall co_thunk(void *coentry) {
((void (*)(void))coentry)();
}
cothread_t co_active() {
if(!co_active_) {
ConvertThreadToFiber(0);
co_active_ = GetCurrentFiber();
}
return co_active_;
}
cothread_t co_create(unsigned int heapsize, void (*coentry)(void)) {
if(!co_active_) {
ConvertThreadToFiber(0);
co_active_ = GetCurrentFiber();
}
return (cothread_t)CreateFiber(heapsize, co_thunk, (void*)coentry);
}
void co_delete(cothread_t cothread) {
DeleteFiber(cothread);
}
void co_switch(cothread_t cothread) {
co_active_ = cothread;
SwitchToFiber(cothread);
}
#ifdef __cplusplus
}
#endif

View File

@ -1,80 +0,0 @@
/*
libco.ucontext (2007-09-08)
author: byuu
license: public domain
*/
#include <stdlib.h>
#include <ucontext.h>
#include "../libco.h"
//WARNING: the overhead of POSIX ucontext is very high,
//averaging ~450x that of standard subroutine calls.
//(tested on FreeBSD 6.2-RELEASE)
//By contrast, on the same system, libco_x86's overhead
//is ~7.25x standard subroutine calls; or fifty times faster.
//
//This library only exists for two reasons:
//1 - as an initial test for the viability of a ucontext implementation
//2 - to demonstrate the power and speed of libco over existing implementations,
// such as pth (which defaults to wrapping ucontext on unix targets)
//
//Use this library only as a *last resort*
struct cothread_struct {
ucontext_t cohandle;
void (*coentry)();
};
cothread_t __co_active = 0, __co_primary = 0;
void co_entrypoint(cothread_t cothread);
void co_init();
/*****
* library functions
*****/
cothread_t co_active() {
if(__co_primary == 0)co_init();
return __co_active;
}
cothread_t co_create(unsigned int heapsize, void (*coentry)()) {
if(__co_primary == 0)co_init();
cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct));
thread->coentry = coentry;
getcontext(&thread->cohandle);
heapsize += 512;
thread->cohandle.uc_stack.ss_sp = (char*)malloc(heapsize);
thread->cohandle.uc_stack.ss_size = heapsize;
makecontext(&thread->cohandle, (void (*)())co_entrypoint, 1, thread);
return (cothread_t)thread;
}
void co_delete(cothread_t cothread) {
cothread_struct *thread = (cothread_struct*)cothread;
free(thread->cohandle.uc_stack.ss_sp);
free(thread);
}
void co_switch(cothread_t cothread) {
cothread_struct *active = (cothread_struct*)__co_active;
cothread_struct *swap = (cothread_struct*)cothread;
__co_active = cothread;
swapcontext(&active->cohandle, &swap->cohandle);
}
/*****
* internal functions
*****/
void co_entrypoint(cothread_t cothread) {
((cothread_struct*)cothread)->coentry();
}
void co_init() {
cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct));
thread->coentry = 0;
getcontext(&thread->cohandle);
__co_active = __co_primary = (cothread_t)thread;
}

View File

@ -1,66 +0,0 @@
/*
libco.win (2007-09-08)
author: byuu
license: public domain
*/
#define WINVER 0x0400
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include "../libco.h"
struct cothread_struct {
void *cohandle;
void (*coentry)();
};
cothread_t __co_active = 0, __co_primary = 0;
void __stdcall co_entryproc(void*);
cothread_t co_init();
/*****
* library functions
*****/
cothread_t co_active() {
if(__co_primary == 0)co_init();
return __co_active;
}
cothread_t co_create(unsigned int heapsize, void (*coentry)()) {
if(__co_primary == 0)co_init();
cothread_struct *s = (cothread_struct*)malloc(sizeof(cothread_struct));
s->coentry = coentry;
s->cohandle = CreateFiber(heapsize + 512, co_entryproc, (void*)s);
return (cothread_t)s;
}
void co_delete(cothread_t cothread) {
cothread_struct *s = (cothread_struct*)cothread;
DeleteFiber(s->cohandle);
free(cothread);
}
void co_switch(cothread_t cothread) {
__co_active = cothread;
cothread_struct *s = (cothread_struct*)cothread;
SwitchToFiber(s->cohandle);
}
/*****
* internal functions
*****/
void __stdcall co_entryproc(void *cothread) {
((cothread_struct*)cothread)->coentry();
}
cothread_t co_init() {
ConvertThreadToFiber(0);
cothread_struct *s = (cothread_struct*)malloc(sizeof(cothread_struct));
s->coentry = 0;
s->cohandle = GetCurrentFiber();
__co_active = __co_primary = (cothread_t)s;
return __co_active;
}

View File

@ -1,146 +0,0 @@
;*****
;libco.x86-64 (2007-12-11)
;author: byuu
;license: public domain
;
;cross-platform x86-64 implementation of libco
;thanks to Aaron Giles and Joel Yliluoma for various optimizations
;thanks to Lucas Newman and Vas Crabb for assistance with OS X support
;
;[ABI compatibility]
;- SystemV ( http://refspecs.freestandards.org/elf/x86_64-SysV-psABI.pdf )
;- gcc; mac os x; x86-64
;- gcc; linux; x86-64
;- gcc; freebsd; x86-64
;
;[nonvolatile registers]
;- rsp, rbp, rbx, r12, r13, r14, r15
;
;[volatile registers]
;- rax, rcx, rdx, r8, r9, r10, r11, rdi, rsi
;- st0 - st7
;- xmm0 - xmm15
;*****
;*****
;linker-specific name decorations
;*****
%ifdef OSX
%define malloc _malloc
%define free _free
%define co_active _co_active
%define co_create _co_create
%define co_delete _co_delete
%define co_switch _co_switch
%endif
bits 64
section .bss
align 8
co_primary_buffer resb 512
section .data
align 8
co_active_context dq co_primary_buffer
section .text
extern malloc
extern free
global co_active
global co_create
global co_delete
global co_switch
;*****
;extern "C" cothread_t co_active();
;return = rax
;*****
align 16
co_active:
mov rax,[co_active_context wrt rip]
ret
;*****
;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
;rdi = heapsize
;rsi = coentry
;return = rax
;*****
align 16
co_create:
;create heap space (stack + context)
add rdi,512 ;allocate extra memory for contextual info
push rdi ;backup volatile registers before malloc call
push rsi
sub rsp,8 ;SSE 16-byte stack alignment
call malloc ;rax = malloc(rdi)
add rsp,8
pop rsi ;restore volatile registers
pop rdi
add rdi,rax ;set rdi to point to top of stack heap
and rdi,-16 ;force 16-byte alignment of stack heap
;store thread entry point + registers, so that first call to co_switch will execute coentry
mov qword[rdi-8],0 ;crash if entry point returns
mov qword[rdi-16],rsi ;entry point
mov qword[rdi-24],0 ;r15
mov qword[rdi-32],0 ;r14
mov qword[rdi-40],0 ;r13
mov qword[rdi-48],0 ;r12
mov qword[rdi-56],0 ;rbx
mov qword[rdi-64],0 ;rbp
sub rdi,64
;initialize context memory heap and return
mov [rax],rdi ;*cothread_t = stack heap pointer (rsp)
ret ;return allocated memory block as thread handle
;*****
;extern "C" void co_delete(cothread_t cothread);
;rdi = cothread
;*****
align 16
co_delete:
jmp free ;free(rdi)
;*****
;extern "C" void co_switch(cothread_t cothread);
;rdi = cothread
;*****
align 16
co_switch:
mov rax,[co_active_context wrt rip] ;backup current context
mov [co_active_context wrt rip],rdi ;set new active context
push rbp
push rbx
push r12
push r13
push r14
push r15
mov [rax],rsp
mov rsp,[rdi]
pop r15
pop r14
pop r13
pop r12
pop rbx
pop rbp
ret

View File

@ -1,155 +0,0 @@
;*****
;libco.x86 (2007-12-11)
;author: byuu
;license: public domain
;
;cross-platform x86 implementation of libco
;thanks to Aaron Giles and Joel Yliluoma for various optimizations
;thanks to Lucas Newman and Vas Crabb for assistance with OS X support
;
;[ABI compatibility]
;- visual c++; windows; x86
;- mingw; windows; x86
;- gcc; mac os x; x86
;- gcc; linux; x86
;- gcc; freebsd; x86
;
;[nonvolatile registers]
;- esp, ebp, edi, esi, ebx
;
;[volatile registers]
;- eax, ecx, edx
;- st0 - st7
;- xmm0 - xmm15
;*****
;*****
;linker-specific name decorations
;*****
%ifdef WIN
%define malloc _malloc
%define free _free
%define co_active @co_active@0
%define co_create @co_create@8
%define co_delete @co_delete@4
%define co_switch @co_switch@4
%endif
%ifdef OSX
%define malloc _malloc
%define free _free
%define co_active _co_active
%define co_create _co_create
%define co_delete _co_delete
%define co_switch _co_switch
%endif
bits 32
section .bss
align 4
co_primary_buffer resb 512
section .data
align 4
co_active_context dd co_primary_buffer
section .text
extern malloc
extern free
global co_active
global co_create
global co_delete
global co_switch
;*****
;extern "C" cothread_t fastcall co_active();
;return = eax
;*****
align 16
co_active:
mov eax,[co_active_context]
ret
;*****
;extern "C" cothread_t fastcall co_create(unsigned int heapsize, void (*coentry)());
;ecx = heapsize
;edx = coentry
;return = eax
;*****
align 16
co_create:
;create heap space (stack + context)
add ecx,512 ;allocate extra memory for contextual info
push ecx ;backup volatile registers before malloc call
push edx
push ecx
call malloc ;eax = malloc(ecx)
add esp,4
pop edx ;restore volatile registers
pop ecx
add ecx,eax ;set edx to point to top of stack heap
and ecx,-16 ;force 16-byte alignment of stack heap
;store thread entry point + registers, so that first call to co_switch will execute coentry
mov dword[ecx-4],0 ;crash if entry point returns
mov dword[ecx-8],edx ;entry point
mov dword[ecx-12],0 ;ebp
mov dword[ecx-16],0 ;esi
mov dword[ecx-20],0 ;edi
mov dword[ecx-24],0 ;ebx
sub ecx,24
;initialize context memory heap and return
mov [eax],ecx ;*cothread_t = stack heap pointer (esp)
ret ;return allocated memory block as thread handle
;*****
;extern "C" void fastcall co_delete(cothread_t cothread);
;ecx = cothread
;*****
align 16
co_delete:
sub esp,8 ;SSE 16-byte stack alignment
push ecx
call free ;free(ecx)
add esp,4+8
ret
;*****
;extern "C" void fastcall co_switch(cothread_t cothread);
;ecx = cothread
;*****
align 16
co_switch:
mov eax,[co_active_context] ;backup current context
mov [co_active_context],ecx ;set new active context
push ebp
push esi
push edi
push ebx
mov [eax],esp
mov esp,[ecx]
pop ebx
pop edi
pop esi
pop ebp
ret

View File

102
sjlj.c Normal file
View File

@ -0,0 +1,102 @@
/*
libco.sjlj (2008-01-28)
author: Nach
license: public domain
*/
/*
* Note this was designed for UNIX systems. Based on ideas expressed in a paper
* by Ralf Engelschall.
* For SJLJ on other systems, one would want to rewrite springboard() and
* co_create() and hack the jmb_buf stack pointer.
*/
#define LIBCO_C
#include "../libco.h"
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
sigjmp_buf context;
void (*coentry)(void);
void *stack;
} cothread_struct;
static thread_local cothread_struct co_primary;
static thread_local cothread_struct *creating, *co_running = 0;
static void springboard(int ignored) {
if(sigsetjmp(creating->context, 0)) {
co_running->coentry();
}
}
cothread_t co_active() {
if(!co_running) co_running = &co_primary;
return (cothread_t)co_running;
}
cothread_t co_create(unsigned int size, void (*coentry)(void)) {
if(!co_running) co_running = &co_primary;
cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct));
if(thread) {
struct sigaction handler;
struct sigaction old_handler;
stack_t stack;
stack_t old_stack;
thread->coentry = thread->stack = 0;
stack.ss_flags = 0;
stack.ss_size = size;
thread->stack = stack.ss_sp = malloc(size);
if(stack.ss_sp && !sigaltstack(&stack, &old_stack)) {
handler.sa_handler = springboard;
handler.sa_flags = SA_ONSTACK;
sigemptyset(&handler.sa_mask);
creating = thread;
if(!sigaction(SIGUSR1, &handler, &old_handler)) {
if(!raise(SIGUSR1)) {
thread->coentry = coentry;
}
sigaltstack(&old_stack, 0);
sigaction(SIGUSR1, &old_handler, 0);
}
}
if(thread->coentry != coentry) {
co_delete(thread);
thread = 0;
}
}
return (cothread_t)thread;
}
void co_delete(cothread_t cothread) {
if(cothread) {
if(((cothread_struct*)cothread)->stack) {
free(((cothread_struct*)cothread)->stack);
}
free(cothread);
}
}
void co_switch(cothread_t cothread) {
if(!sigsetjmp(co_running->context, 0)) {
co_running = (cothread_struct*)cothread;
siglongjmp(co_running->context, 1);
}
}
#ifdef __cplusplus
}
#endif

67
ucontext.c Normal file
View File

@ -0,0 +1,67 @@
/*
libco.ucontext (2008-01-28)
author: Nach
license: public domain
*/
/*
* WARNING: the overhead of POSIX ucontext is very high,
* assembly versions of libco or libco_sjlj should be much faster
*
* This library only exists for two reasons:
* 1 - as an initial test for the viability of a ucontext implementation
* 2 - to demonstrate the power and speed of libco over existing implementations,
* such as pth (which defaults to wrapping ucontext on unix targets)
*
* Use this library only as a *last resort*
*/
#define LIBCO_C
#include "../libco.h"
#include <stdlib.h>
#include <ucontext.h>
#ifdef __cplusplus
extern "C" {
#endif
static thread_local ucontext_t co_primary;
static thread_local ucontext_t *co_running = 0;
cothread_t co_active() {
if(!co_running) co_running = &co_primary;
return (cothread_t)co_running;
}
cothread_t co_create(unsigned int heapsize, void (*coentry)(void)) {
if(!co_running) co_running = &co_primary;
ucontext_t *thread = (ucontext_t*)malloc(sizeof(ucontext_t));
if(thread) {
if((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = malloc(heapsize))) {
thread->uc_link = co_running;
thread->uc_stack.ss_size = heapsize;
makecontext(thread, coentry, 0);
} else {
co_delete((cothread_t)thread);
thread = 0;
}
}
return (cothread_t)thread;
}
void co_delete(cothread_t cothread) {
if(cothread) {
if(((ucontext_t*)cothread)->uc_stack.ss_sp) { free(((ucontext_t*)cothread)->uc_stack.ss_sp); }
free(cothread);
}
}
void co_switch(cothread_t cothread) {
ucontext_t *old_thread = co_running;
co_running = (ucontext_t*)cothread;
swapcontext(old_thread, co_running);
}
#ifdef __cplusplus
}
#endif

81
x86-64.c Normal file
View File

@ -0,0 +1,81 @@
/*
libco.x86-64 (2008-01-28)
author: byuu
license: public domain
*/
#define LIBCO_C
#include "../libco.h"
#include <assert.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
static thread_local long co_active_buffer[32];
static thread_local cothread_t co_active_ = 0;
static void crash() {
assert(0); /* called only if cothread_t entrypoint returns */
}
cothread_t co_active() {
if(!co_active_) co_active_ = &co_active_buffer;
return co_active_;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
cothread_t handle;
assert(sizeof(long) == 8);
if(!co_active_) co_active_ = &co_active_buffer;
size += 128; /* allocate additional space for storage */
size &= ~15; /* align stack to 16-byte boundary */
if(handle = (cothread_t)calloc(size, 1)) {
long *p = (long*)((char*)handle + size); /* seek to top of stack */
*--p = (long)crash; /* crash if entrypoint returns */
*--p = (long)entrypoint; /* start of function */
*(long*)handle = (long)p; /* stack pointer */
}
return handle;
}
void co_delete(cothread_t handle) {
free(handle);
}
void co_switch(cothread_t to) {
register long stack = *(long*)to; /* stack[0] = "to" thread entry point */
register cothread_t from = co_active_;
co_active_ = to;
__asm__ __volatile__(
"movq %%rsp,(%1) \n\t" /* save old stack pointer */
"movq (%0),%%rsp \n\t" /* load new stack pointer */
"addq $8,%%rsp \n\t" /* "pop" return address off stack */
"movq %%rbp, 8(%1) \n\t" /* backup non-volatile registers */
"movq %%rbx,16(%1) \n\t"
"movq %%r12,24(%1) \n\t"
"movq %%r13,32(%1) \n\t"
"movq %%r14,40(%1) \n\t"
"movq %%r15,48(%1) \n\t"
"movq 8(%0),%%rbp \n\t" /* restore non-volatile registers */
"movq 16(%0),%%rbx \n\t"
"movq 24(%0),%%r12 \n\t"
"movq 32(%0),%%r13 \n\t"
"movq 40(%0),%%r14 \n\t"
"movq 48(%0),%%r15 \n\t"
"jmp *(%2) \n\t" /* jump into "to" thread */
: /* no outputs */
: "r" (to), "r" (from), "r" (stack)
);
}
#ifdef __cplusplus
}
#endif

110
x86.c Normal file
View File

@ -0,0 +1,110 @@
/*
libco.x86 (2008-01-28)
author: byuu
license: public domain
*/
#define LIBCO_C
#include "../libco.h"
#include <assert.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
static thread_local long co_active_buffer[32];
static thread_local cothread_t co_active_ = 0;
static void crash() {
assert(0); /* called only if cothread_t entrypoint returns */
}
cothread_t co_active() {
if(!co_active_) co_active_ = &co_active_buffer;
return co_active_;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
cothread_t handle;
assert(sizeof(long) == 4);
if(!co_active_) co_active_ = &co_active_buffer;
size += 128; /* allocate additional space for storage */
size &= ~15; /* align stack to 16-byte boundary */
if(handle = (cothread_t)calloc(size, 1)) {
long *p = (long*)((char*)handle + size); /* seek to top of stack */
*--p = (long)crash; /* crash if entrypoint returns */
*--p = (long)entrypoint; /* start of function */
*(long*)handle = (long)p; /* stack pointer */
}
return handle;
}
void co_delete(cothread_t handle) {
free(handle);
}
#if defined(__GNUC__)
void co_switch(cothread_t to) {
register long stack = *(long*)to; /* stack[0] = "to" thread entry point */
register cothread_t from = co_active_;
co_active_ = to;
__asm__ __volatile__(
"movl %%esp,(%1) \n\t" /* save old stack pointer */
"movl (%0),%%esp \n\t" /* load new stack pointer */
"addl $4,%%esp \n\t" /* "pop" return address off stack */
"movl %%ebp, 4(%1) \n\t" /* backup non-volatile registers */
"movl %%esi, 8(%1) \n\t"
"movl %%edi,12(%1) \n\t"
"movl %%ebx,16(%1) \n\t"
"movl 4(%0),%%ebp \n\t" /* restore non-volatile registers */
"movl 8(%0),%%esi \n\t"
"movl 12(%0),%%edi \n\t"
"movl 16(%0),%%ebx \n\t"
"jmp *(%2) \n\t" /* jump into "to" thread */
: /* no outputs */
: "r" (to), "r" (from), "r" (stack)
);
}
#elif defined(_MSC_VER)
__declspec(naked) __declspec(noinline)
static void __fastcall co_swap(register cothread_t to, register cothread_t from) {
/* ecx = to, edx = from */
__asm {
mov [edx],esp
mov esp,[ecx]
pop eax
mov [edx+ 4],ebp
mov [edx+ 8],esi
mov [edx+12],edi
mov [edx+16],ebx
mov ebp,[ecx+ 4]
mov esi,[ecx+ 8]
mov edi,[ecx+12]
mov ebx,[ecx+16]
jmp eax
}
}
void co_switch(cothread_t handle) {
register cothread_t co_prev_ = co_active_;
co_swap(co_active_ = handle, co_prev_);
}
#endif
#ifdef __cplusplus
}
#endif